简体   繁体   English

旋转后在Objective-C中重新组织屏幕

[英]Reorganise a screen in objective-c after rotation

I am creating an iPhone application, and in one view I am planning to have a split screen. 我正在创建一个iPhone应用程序,并且打算在一个视图中使用一个分屏。 It will be a map view in the main area of the page, but I want to then display a table underneath the map that shows details of the nearest hits to the user. 这将是页面主要区域中的地图视图,但是我想在地图下方显示一个表格,该表格向用户显示最近匹配的详细信息。

So the layout in portrait view will be like this: 因此,纵向视图中的布局将如下所示:

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

With a 60/40 split between the top mapview area and the bottom table area. 顶部Mapview区域和底部表格区域之间以60/40的比例分配。

When I rotate the phone, I need this layout to re-adjust and rotate sensibly, so that it adjusts to: 旋转手机时,我需要此布局重新调整并合理旋转,以便将其调整为:

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

With the mapview in the left area and the table at the right. mapview位于左侧区域,表格位于右侧。

And, of course, re-layout between the two views smoothly as the user rotates their device. 而且,当然,当用户旋转设备时,可以在两个视图之间平滑地重新布局。

What is the best way to handle this in code? 用代码处理此问题的最佳方法是什么? I am not sure what is the best way to re-layout the screen on rotation? 我不确定旋转时重新布局屏幕的最佳方法是什么?

Is it good practice to just resize and move the two views using, eg for the top view: 调整大小和移动两个视图是否是一种好习惯,例如用于顶视图:

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

And then use the following to move and redraw this when I detect an orientation change: 当我检测到方向改变时,使用以下命令来移动并重绘该方向:

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

You want your UI to adapt. 您希望您的用户界面适应。 Apple wants your UI to adapt. 苹果希望您的用户界面适应。

You could write the code to handle orientation changes and lay the views out yourself, but you might miss an edge case, or it might not work on a future device or with upcoming functionality (such as split-screen multitasking). 您可以编写代码来处理方向更改并自行布置视图,但是您可能会遗漏边缘情况,或者在将来的设备或即将推出的功能(例如分屏多任务)上可能无法使用。

Instead of trying to write code to handle this yourself, you may want to take advantage of UIStackView . 您可能想要利用UIStackView ,而不是尝试自己编写代码来自行处理。

Stack views let you leverage the power of Auto Layout, creating user interfaces that can dynamically adapt to the device's orientation , screen size, and any changes in the available space. 堆栈视图使您可以利用自动版式的功能,创建可以动态适应设备方向 ,屏幕尺寸以及可用空间中任何更改的用户界面。

You can achieve the exact same behaviour by using Autolayout with multiple Arrays of Constraints. 通过将自动布局与多个约束数组一起使用,可以实现完全相同的行为。 Just save yourself a reference of the applied NSLayoutConstraint 's. 只需保存自己对所应用NSLayoutConstraint的引用即可 Lets Assume you have declared your Views as a property and synthesized them like listed below. 假设您已将Views声明为属性,并像下面列出的那样对它们进行了合成。

@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

Just set up your Views and add them as Subviews to UIViewController.view . 只需设置您的视图并将它们作为子视图添加到UIViewController.view即可 After this you fill up your Arrays portraitLayoutConstraints and landscapeLayoutConstraint with the appropriate Constraints. 之后,使用适当的约束填充Array portraitLayoutConstraintslandscapeLayoutConstraint

- (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]];

}

In my current Project I add the portraitLayoutConstraints to the view. 在我当前的项目中,我将portraitLayoutConstraints添加到视图中。 After this I deactivate the Constraints from the same Array. 此后,我从同一阵列取消约束。 Afterwards I can add the landscapeLayoutConstraint and deactivate them as well. 之后,我可以添加landscapeLayoutConstraint并停用它们。 This is for sure not the most elegant way of implement the intended behaviour, but it does the trick for me. 当然,这不是实现预期行为的最优雅的方法,但是它对我有用。 Having my Constraints set, I can deactivate and activate them, as I need them. 设置好约束后,可以根据需要停用和激活它们。

- (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];
    }
}

In my special Case I wanted to react to the change of the DeviceOrientation, so I added an Observer for UIApplicationWillChangeStatusBarOrientationNotification in my viewDidLoad and deactivate/activate the Constraints when the DeviceOrientation changes. 在我的特殊情况下,我想对DeviceOrientation的更改做出反应,因此我在viewDidLoad中UIApplicationWillChangeStatusBarOrientationNotification添加了一个Observer,并在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];
}

Maybe this will help to find a solution for your Problem. 也许这将有助于找到您的问题的解决方案。 Another difficulty I see in the available indicating range in Portrait Orientation. 我在人像方向的可用指示范围中看到的另一个困难。 If you consider to hug the content inside a scrollview check out this answer of mine: Adding programatically created views into scrollview vertically . 如果您想拥抱滚动视图中的内容,请查看我的以下答案: 将以编程方式创建的视图垂直添加到scrollview中 Also I would recommend the WWDC2015 Session on Mysteries of Auto Layout and the corresponding AstroLayout Sample code . 我也建议WWDC2015 自动布局之谜会议以及相应的AstroLayout示例代码

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

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