iOS change auto layout constraints when device rotates
Solution 1
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.
Solution 2
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.
Solution 3
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;
}
}
Related videos on Youtube
Comments
-
vitaminwater over 1 year
I want to modify the layout constraints when the device rotates. My
UIViewController
is composed of 2UIViews
, 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...
-
Waseem Shah almost 11 yearsplease add your code here
-
vitaminwater almost 11 years@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 almost 11 years@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 !
-
David H about 10 yearsYou should accept one of the answers - probably Rob's - as he for sure answered your question.
-
-
vitaminwater almost 11 yearslayoutSubviews is an UIView method, not sure that's the way to go, but thanks ! This project has been shipped now, so I can't really test it anyway, the closest approach to what you are proposing would be to use the viewWillLayoutSubviews from the UIViewController, I think I had tried that without success..
-
rob mayoff over 10 yearsFirst, you need to call
[super layoutSubviews]
if you're using autolayout. Second, you don't want to modify your constraints inlayoutSubviews
, becauselayoutSubviews
is sent after the system has solved the constraints. Changing the constraints here will trigger another layout pass (to solve the new constraints) on the next turn of the run loop. -
vitaminwater over 10 yearsI feel like you are defeating the purpose of autolayout there, if you set a fixed width and height, and add top/left space for positionning, your doing nothing more than spring & struts. of course there are no borken constraints by doing this as you are not adding any constraints linking your views together; for example, if you have to manage more than one screen size/ratio, you'd have to make special cases, which is what autolayout tends to avoid !
-
Eugene Tartakovsky over 10 yearsI think it is just the special case. You need fixed size and dynamic position - you can get it. You need dynamic size - you can get it too. Autolayout allows you to implement dynamics when and where you want. Spring & struts - not.
-
Matt Mc over 10 yearsLooks like the correct method to implement/override here would be
viewWillLayoutSubviews
. -
Ben Packard over 10 yearsThis is very cool and works flawlessly. In my implementation I am iterating over [view constraints] and removing each one before adding the orientation-specific constraints. This is a wholesale swap and the animated change looks great.
-
Tenfour04 almost 10 yearsDo you have to subclass every view that will have its constraints modified, or can you somehow do this completely from the view controller? It seems that a very, very common situation would be to change some widths and heights for rotation changes, but would be quite ugly if you have to fill out your layout with multiple custom classes for many interior views.
-
Tenfour04 almost 10 yearsThere are a few special cases where you need to mix in a few hard-coded sizes that react to rotations. For example, in a scroll view that has paging turned on, where you want the inner views to be the same width as the screen so they each line up with the screen when paged to. That's not worth turning off autolayout for as long as there is a workaround like this. Autolayout is a huge time saver for supporting all the different device resolutions, and it is likely that future devices will add even more resolutions to support.
-
rob mayoff almost 10 yearsYou could make a custom class for the top-level view and give it outlets to all of the subviews that need modified constraints. Then you can set up all the constraints in that custom class's
updateConstraints
method. -
nortchuck over 8 yearsThis works great. Simply just set the new constraint constants and voila! Thanks!
-
Mohammad Zaid Pathan over 8 years@robmayoff, I've created UIView subclass, and Registered Notification, Taken outlet of my view(i.e. ImageView), now when notification fired, i've setNeedsUpdateConstraints on That ImageView, and [[self ImageView] updateConstraints] set on updateConstraints method, but nothing happened... What should i do.? One thing to notice that i've given constraints in xib for Portrait and Landscape. This is working fine in iOS8 but do not work in iOS7.
-
Sebastian Roth about 7 years
willRotateToInterfaceOrientation:duration:
is deprecated now? -
rob mayoff about 7 yearsHave you checked the documentation to see what it is replaced with?
-
petrsyn about 7 yearsIt was replaced with
viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)