在旋转后重新组织objective-c中的屏幕

时间:2015-07-03 13:21:14

标签: ios objective-c

我正在创建一个iPhone应用程序,在一个视图中我计划有一个分屏。它将是页面主要区域中的地图视图,但我想在地图下方显示一个表格,该表格显示最近用户点击的详细信息。

因此纵向视图中的布局将如下所示:

------------
|          |
|          |
|          |
|          |
|          |
|          |
|          |
------------
|          |
|          |
|          |
------------

在顶部mapview区域和底部表区域之间进行60/40分割。

当我旋转手机时,我需要这种布局来重新调整和合理旋转,以便调整为:

---------------------------
|               |         |
|               |         |
|               |         |
|               |         |
|               |         |
|               |         |
|               |         |
|               |         |
---------------------------

左侧区域的mapview和右侧的表格。

当然,当用户旋转设备时,可以平滑地重新布局两个视图。

在代码中处理此问题的最佳方法是什么?我不确定在旋转时重新布局屏幕的最佳方法是什么?

使用例如顶视图来调整和移动两个视图是不错的做法:

mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight*0.6)];

然后在检测到方向更改时使用以下内容移动并重绘:

mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, screenWidth*0.6, screenHeight)];

2 个答案:

答案 0 :(得分:0)

您希望自己的UI适应。 Apple wants your UI to adapt.

您可以编写代码来处理方向更改并自己创建视图,但是您可能会错过边缘情况,或者它可能无法在将来的设备或即将推出的功能(例如分屏多任务处理)上运行。 / p>

您可能希望利用UIStackView而不是尝试编写代码来处理此问题。

  

通过堆栈视图,您可以利用自动布局的强大功能,创建可以动态适应设备方向的用户界面,屏幕大小以及可用空间的任何变化。

答案 1 :(得分:0)

使用具有多个约束数组的Autolayout可以实现完全相同的行为。只需保存自己应用的 NSLayoutConstraint 的引用。让我们假设您已将视图声明为属性并合成它们,如下所示。

@interface YourFancySplitScreenViewController ()
    @property (nonatomic, strong) AwesomeMapView* myAwesomeMapView;
    @property (nonatomic, strong) CoolTableView* myCoolTableView;
    @property (nonatomic, strong) NSMutableArray* portraitLayoutConstraints;
    @property (nonatomic, strong) NSMutableArray* landscapeLayoutConstraint;
@end

@implementation YourFancySplitScreenViewController
@synthesize myAwesomeMapView, myCoolTableView;
@synthesize portraitLayoutConstraints, landscapeLayoutConstraint;

// [...]

@end

只需设置您的视图并将其添加为 UIViewController.view 的子视图。在此之后,使用适当的约束条件填充数组 portraitLayoutConstraints landscapeLayoutConstraint

- (void) getYourConstraintsRight {
    // The Views you want to manipulate with your Constraints
    NSDictionary* viewsDictionary = NSDictionaryOfVariableBindings(myAwesomeMapView, myCoolTableView);

    self.portraitLayoutConstraints = [[NSMutableArray alloc] init];
    self.landscapeLayoutConstraint = [[NSMutableArray alloc] init];

    // Now just add The Constraints to your Arrays, eg. with constraintsWithVisualFormat
    [self.portraitLayoutConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"Your terrific portrait Contstraints" options:0 metrics:0 views:viewsDictionary]];
    [self.landscapeLayoutConstraint addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"Your even better landscape Contstraints" options:0 metrics:0 views:viewsDictionary]];

}

在我目前的项目中,我将 portraitLayoutConstraints 添加到视图中。在此之后,我从同一个数组中取消激活约束。之后我可以添加 landscapeLayoutConstraint 并停用它们。这肯定不是实现预期行为的最优雅方式,但它对我有用。设置好Constraints后,我可以根据需要停用并激活它们。

- (void) addYourConstraintsToTheView {
    // place some ugly code here
    [self.view addConstraints:self.landscapeLayoutConstraint];
    [NSLayoutConstraint deactivateConstraints:self.landscapeLayoutConstraint];
    [self.view addConstraints:self.portraitLayoutConstraints];
    [NSLayoutConstraint deactivateConstraints:self.portraitLayoutConstraints];
}

- (void) setYourConstraintsAccordingToTheUIInterfaceOrientation {
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];

    if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
        [NSLayoutConstraint activateConstraints:self.landscapeLayoutConstraint];
    }
    if (orientation == UIInterfaceOrientationPortrait) {
        [NSLayoutConstraint activateConstraints:self.portraitLayoutConstraints];
    }
}

在我的特殊情况下,我想对DeviceOrientation的更改作出反应,因此我在 viewDidLoad 中添加了 UIApplicationWillChangeStatusBarOrientationNotification 的观察者,并在此时停用/激活约束DeviceOrientation更改。

- (void)viewDidLoad {
    [super viewDidLoad];
    // Maybe you want to set your views here
    // then add the Constraints
    [self getYourConstraintsRight];
    [self addYourConstraintsToTheView];
    [self setYourConstraintsAccordingToTheUIInterfaceOrientation];

    // Observe your Notifications
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notification_OrientationWillChange:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];

}

- (void)notification_OrientationWillChange:(NSNotification*)notification {
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];;

    if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
        [self animateToPortrait];
    }
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
        [self animateToLandscape];
    }
}

- (void)animateToPortrait {
    [UIView animateWithDuration:1.0 animations:^{
        [NSLayoutConstraint deactivateConstraints: self.landscapeLayoutConstraint];
        [NSLayoutConstraint activateConstraints: self.portraitLayoutConstraints];
    }];
    [self.view layoutIfNeeded];
}

- (void)animateToLandscape {
    [UIView animateWithDuration:1.0 animations:^{
        [NSLayoutConstraint deactivateConstraints: self.portraitLayoutConstraints];
        [NSLayoutConstraint activateConstraints: self.landscapeLayoutConstraint];
    }];
    [self.view layoutIfNeeded];
}

// You want to remove the Observer
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisapper:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self.view];
}

也许这有助于为您的问题找到解决方案。我在Portrait Orientation的可用指示范围中看到的另一个困难。如果您考虑拥抱滚动视图中的内容,请查看我的答案:Adding programatically created views into scrollview vertically。我还建议Mysteries of Auto Layout上的WWDC2015会话和相应的AstroLayout Sample code