Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS change auto layout constraints when device rotates

I want to modify the layout constraints when the device rotates. My UIViewController is composed of 2 UIViews, in landscape they are horizontally aligned, and in portrait they are vertically aligned.

It does work actually, in willAnimateRotationToInterfaceOrientation, I remove the desired constraints and replaced them with others to have the right layout...

But there are problems, during rotation auto layout starts breaking constraints before willAnimateRotationToInterfaceOrientation is called, so where are we meant to replace our constraints when the device reorientation occurs ?

Another issue is performance, after a few rotations the system doesn't break anymore constraints, but I have a huge performance drop, especially in portrait mode...

like image 462
vitaminwater Avatar asked Dec 06 '12 08:12

vitaminwater


3 Answers

There is very good explanation of auto-layout and rotations in Matthijs Hollemans post. You can find it here: http://www.raywenderlich.com/20881/beginning-auto-layout-part-1-of-2

Usually, you need about 4 constraints to correctly position your view. If my views have constant size i prefer to pin height and width. After that you can use Leading and Top space constraints to do whatever you want. For example, you can set IBOutlets for leading and top space constraints for your views:

@interface ViewController : UIViewController {
    IBOutlet NSLayoutConstraint *_leadingSpaceConstraint;
    IBOutlet NSLayoutConstraint *_topSpaceConstraint;
}

Then control-drag from outlet to your constraint. Now you can directly change your view constraint from code:

_leadingSpaceConstraint.constant = NEW_CONSTRAINT_VALUE;

To commit your changes you need to call:

[self.view layoutIfNeeded];

And if you want to do it animated:

[UIView animateWithDuration:0.25
                 animations:^{
                     [self.view layoutIfNeeded];
                 }];

I think it will work in willAnimateRotationToInterfaceOrientation, because you don't need to break any constraints with this approach.

Some example: You have two square view in portrait orientation, one under another. Set their "leading space to superview" constraints to 20, for example. Then set "top space to superview constraint" to 20 for first view and to 120 for second. It will be our default setup.

Then, after rotation you need to recalculate your constraints. Now set both of top constraints to 20, and leading constraints to 20 and 120 respectively. Then commit changes with layoutIfNeeded.

I hope it will help.

like image 43
Eugene Tartakovsky Avatar answered Nov 06 '22 08:11

Eugene Tartakovsky


In willRotateToInterfaceOrientation:duration:, send setNeedsUpdateConstraints to any view that needs its constraints modified.

Alternatively, make a UIView subclass. In your subclass, register to receive UIApplicationWillChangeStatusBarOrientationNotification. When you receive the notification, send yourself setNeedsUpdateConstraints.

This sets the needsUpdateConstraints flag on the view. Before the system performs layout (by sending layoutSubviews messages), it sends an updateConstraints message to any view that has the needsUpdateConstraints flag set. This is where you should modify your constraints. Make a UIView subclass and override updateConstraints to update your constraints.

like image 56
rob mayoff Avatar answered Nov 06 '22 06:11

rob mayoff


override -(void) viewWillLayoutSubviews in your UIViewController to update your constraints as below code:

-(void) viewWillLayoutSubviews {
     switch(self.interfaceorientation)
     {
          case UIInterfaceOrientationLandscapeLeft:

              break;
          case UIInterfaceOrientationLandscapeRight:

              break;

          case UIDeviceOrientationPortrait:

              break;

          case UIDeviceOrientationPortraitUpsideDown:

              break;

     }
}
like image 2
MuhammadBassio Avatar answered Nov 06 '22 07:11

MuhammadBassio