简体   繁体   English

自动版式,约束和旋转

[英]AutoLayout, constraints, and rotation

I'm having an issue with auto layout and constraints and could use some help. 我在自动布局和约束方面遇到问题,可以寻求帮助。

I am running this application on an iPad. 我正在iPad上运行此应用程序。 I have a window that contains two views, a UIWebView and an MKMapView. 我有一个包含两个视图的窗口,一个UIWebView和一个MKMapView。 Both of those views are set up in IB, and Auto Layout is turned on. 这两个视图都在IB中设置,并且自动版式已启用。 The UIWebView is positioned at the top of the window and the MKMapView is at the bottom. UIWebView位于窗口的顶部,而MKMapView位于窗口的底部。 Each view takes up almost half of the window. 每个视图几乎占据一半的窗口。 The UIWebView has the following constraints set up in IB: NSLayoutAttributeTop to Superview equal to 0, Leading Edge to Superview equal to 0, Trailing Edge to Superview equal to 0, and NSLayoutAttributeBottom to Superview equal to 480. The MKMapView has the following constraints set up in IB: NSLayoutAttributeTop to Superview equal to 480, Leading Edge to Superview equal to 0, Trailing Edge to Superview equal to 0, and NSLayoutAttributeBottom to Superview equal to 0. UIWebView在IB中设置了以下约束:SuperLayout的NSLayoutAttributeTop等于0,Superview的前导边缘等于0,Superview的后缘等于0,Superview的NSLayoutAttributeBottom等于480。MKMapView设置了以下约束在IB中:超级视图的NSLayoutAttributeTop等于480,超级视图的前导边缘等于0,超级视图的后沿等于0,超级视图的NSLayoutAttributeBottom等于0。

When the window is loaded, the MKMapView is actually removed, since I want the UIWebView to take up the entire screen, because there is no data to display in the map view. 加载窗口后,实际上会删除MKMapView,因为我希望UIWebView占据整个屏幕,因为在地图视图中没有数据可显示。 This is done in my updateDetailViews function: 这是在我的updateDetailViews函数中完成的:

- (void)updateDetailViews
{
displayHeight = self.maximumUsableFrame.size.height;
viewDistance=displayHeight/2+centerMapButton.frame.size.height/2+16;

[detailMapView setTranslatesAutoresizingMaskIntoConstraints:NO];
[directoryWebView setTranslatesAutoresizingMaskIntoConstraints:NO];

if (mapViewVisible==true) {
    webViewDistFromBottomDefault=viewDistance;
    webViewDistFromBottom.constant=viewDistance;
    mapViewDistFromTopDefault=viewDistance;
    mapViewDistFromTop.constant=viewDistance;

}
else {
    [detailMapView removeFromSuperview];
    webViewDistFromBottomDefault=0;
    webViewDistFromBottom.constant=0;
    mapViewDistFromTopDefault=viewDistance;
    mapViewDistFromTop.constant=viewDistance;
}

[detailMapView setNeedsUpdateConstraints];
[UIView animateWithDuration:0.25f animations:^{
    [self.detailMapView layoutIfNeeded];
}];

}

After the MKMapView is removed, the NSLayoutAttributeBottom attribute of UIWebview is set to 0, and it fills the entire screen. 删除MKMapView之后,UIWebview的NSLayoutAttributeBottom属性设置为0,并且它将填充整个屏幕。 Once there is actual data to show in the map, the MKMapView is then added, and the UIWebView repositioned, along with the necessary constraints, in my displayMapView function: 在地图中显示实际数据后,便会添加MKMapView,并将UIWebView以及必要的约束重新放置在我的displayMapView函数中:

- (void)displayMapView
{
double dblLatitude;
double dblLongitude;


[detailMapView setTranslatesAutoresizingMaskIntoConstraints:NO];
if ([self isMapViewDisplayed]==FALSE) {

    [detailView addSubview:detailMapView];

    NSLayoutConstraint *myConstraint =[NSLayoutConstraint
                                       constraintWithItem:detailMapView
                                       attribute:NSLayoutAttributeTop
                                       relatedBy:NSLayoutRelationEqual
                                       toItem:detailView
                                       attribute:NSLayoutAttributeTop
                                       multiplier:1.0
                                       constant:mapViewDistFromTopDefault];

    [detailView addConstraint:myConstraint];

    //mapViewDistFromTop.constant = mapViewDistFromTopDefault;

    myConstraint =[NSLayoutConstraint
                   constraintWithItem:detailMapView
                   attribute:NSLayoutAttributeBottom
                   relatedBy:NSLayoutRelationEqual
                   toItem:detailView
                   attribute:NSLayoutAttributeBottom
                   multiplier:1.0
                   constant:0];

    [detailView addConstraint:myConstraint];

    myConstraint =[NSLayoutConstraint
                   constraintWithItem:detailMapView
                   attribute:NSLayoutAttributeLeading
                   relatedBy:NSLayoutRelationEqual
                   toItem:detailView
                   attribute:NSLayoutAttributeLeading
                   multiplier:1.0
                   constant:0];

    [detailView addConstraint:myConstraint];

    myConstraint =[NSLayoutConstraint
                   constraintWithItem:detailMapView
                   attribute:NSLayoutAttributeTrailing
                   relatedBy:NSLayoutRelationEqual
                   toItem:detailView
                   attribute:NSLayoutAttributeTrailing
                   multiplier:1.0
                   constant:0];

    [detailView addConstraint:myConstraint];
    [detailMapView setNeedsUpdateConstraints];

}
[UIView animateWithDuration:.5
                 animations:^{
                     webViewDistFromBottom.constant=webViewDistFromBottomDefault;
                     mapViewDistFromTop.constant=mapViewDistFromTopDefault;
                     [self.directoryWebView layoutIfNeeded];
                     [self.detailMapView layoutIfNeeded];
                 }];

[self updateDetailViews];

...

if ((dblLatitude != 0) && (dblLongitude != 0)) {
    zoomLocation.latitude = dblLatitude;
    zoomLocation.longitude = dblLongitude;

    MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, METERS_PER_MILE, METERS_PER_MILE);
    MKCoordinateRegion adjustedRegion = [detailMapView regionThatFits:viewRegion];
    [detailMapView setRegion:adjustedRegion animated:YES];
}
CLLocationCoordinate2D coordinate;
coordinate.latitude = dblLatitude;
coordinate.longitude = dblLongitude;

...

[detailMapView addAnnotation:annotation];
}

All of this works like I intend. 所有这些工作都符合我的预期。 The problem occurs when the device is rotated. 旋转设备时发生问题。 If I start with the iPad in portrait mode, the webViewDistFromBottom and mapViewDistFromTop constraints are set to 490, due to the updateDetailViews function above which has the following calculations: 如果我以人像模式开始使用iPad,则由于上面的updateDetailViews函数具有以下计算,因此webViewDistFromBottom和mapViewDistFromTop约束设置为490:

displayHeight = self.maximumUsableFrame.size.height;
viewDistance=displayHeight/2+centerMapButton.frame.size.height/2+16;

If the iPad is rotated to landscape, the willAnimateRotationToInterfaceOrientation function is called, which then calls updateDetailViews, which sets viewDistance to 367 (and correspondingly webViewDistFromBottom.constant and mapViewDistFromTop.constant). 如果将iPad旋转到横向,则将调用willAnimateRotationToInterfaceOrientation函数,该函数然后调用updateDetailViews,该方法将viewDistance设置为367(以及相应的webViewDistFromBottom.constant和mapViewDistFromTop.constant)。 The UIWebView on top looks as it should, however, the MKMapView on bottom does not. 顶部的UIWebView看起来应该是应该的,但是底部的MKMapView则没有。 The mapViewDistFromTop constraint is set to 367 (if I output the value to the log), however it appears that it is still set to 490. My updateDetailViews function calls [self.view layoutIfNeeded] (and I have also tried [detailMapView layoutIfNeeded], [detailMapView setNeedsLayout]), but that view does not show up correctly. mapViewDistFromTop约束设置为367(如果我将值输出到日志),但是看来它仍然设置为490。我的updateDetailViews函数调用[self.view layoutIfNeeded](并且我也尝试过[detailMapView layoutIfNeeded], [detailMapView setNeedsLayout]),但该视图无法正确显示。 The distance from the top is too large. 与顶部的距离太大。 If I rotate the iPad back to portrait, it looks fine. 如果我将iPad旋转回纵向,看起来不错。

I also have the same problem if the iPad is started in landscape mode, then rotated to portrait. 如果iPad以横向模式启动,然后旋转为纵向模式,我也会遇到同样的问题。 In landscape mode, the mapViewDistFromTop and webViewDistFromBottom values are 367, and are set to 490 once rotated to portrait. 在横向模式下,mapViewDistFromTop和webViewDistFromBottom值为367,一旦旋转为纵向,则将其设置为490。 However, the MKMapView on the bottom looks as those the distance from the top is still 367, covering too much of the display. 但是,底部的MKMapView看起来与顶部的距离仍然是367,覆盖了太多显示内容。

Any idea what I'm doing wrong? 知道我在做什么错吗? Thanks in advance for any assistance!!! 在此先感谢您的协助!!!

If I understand the question correctly, when in portrait you want a map view, 480 points tall, at the bottom, and if in landscape, you want the web view to take up the whole screen. 如果我对问题的理解正确,那么在纵向模式下,您需要底部为480点的地图视图;在横向模式下,您希望网络视图占据整个屏幕。 An alternative approach would be to just modify the height of the map view (480 in portrait, 0 in landscape). 一种替代方法是仅修改地图视图的高度(纵向为480,横向为0)。 Don't remove the map view, just set its height to 0. And let the existing constraints take care of everything else. 不要删除地图视图,只需将其高度设置为0。让现有的约束处理所有其他事情。 Then there are no adding of modifying of constraints, views, etc. All you need to do is adjust one constant on rotation. 然后,无需添加约束,视图等的修改。您要做的就是在旋转时调整一个常数。 Does that do the job? 这样行吗?

To illustrate this, in this scenario I'm suggesting you set up your constraints (I'll only focus on the vertical constraints) so that they are equivalent to 为了说明这一点,在这种情况下,我建议您设置约束(我将只关注垂直约束),以使它们等效于

V:|[webView][mapView(480)]|

(I'm not suggesting you use VFL to specify the constraints, but it's just the most concise way to articulate the series of constraints I used.) Note, make sure you don't have any extraneous constraints floating around (eg web view bottom constraint to super view, etc.). (我不建议您使用VFL来指定约束,但这只是表达我使用的一系列约束的最简洁的方法。)请注意,请确保您没有任何多余的约束(例如,Web视图底部)限制为超级视图等)。 I'm proposing, in the vertical dimension, just these constraints (web view top to super view, web view bottom to map view top, map view height, and map view bottom to super view). 我在垂直维度上提出了这些限制(Web视图顶部到超级视图,Web视图底部到地图视图顶部,地图视图高度,以及地图视图底部到超级视图)。

Then, define and link an outlet for the height constraint of the mapView : 然后,为mapView的高度约束定义并链接出口:

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *mapViewHeightConstraint;

Finally, on rotation, just change the constant for that constraint: 最后,在旋转时,只需更改该约束的常量即可:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];

    if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation))
        self.mapViewHeightConstraint.constant = 480.0;
    else
        self.mapViewHeightConstraint.constant = 0.0;
}

If I understand the UI you're shooting for, I think that's all you need, eliminating all of that other code in your question. 如果我了解您要拍摄的UI,那么我认为这就是您所需要的,从而消除了问题中的所有其他代码。 I just tested it and it seems to work fine. 我刚刚对其进行了测试,它似乎工作正常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM