48
votes

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...

3
please add your code hereWaseem Shah
@Makleesh : yes you are right a lot of problems emerge when using auto-layout, but I find them quite handy.. anyway, looks it will be the new way of doing things, better get into it now than late.vitaminwater
@Waseem : I don't really have code to post... as I said the constraints are broken even before my code is executed, so I don't really know what code I could post !vitaminwater
You should accept one of the answers - probably Rob's - as he for sure answered your question.David H

3 Answers

55
votes

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.

13
votes

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.

2
votes

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;

     }
}