Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use autolayout to provide different constraints for landscape and portrait orientations?

Is it possible to change the constraints when the device is rotated? How might this be achieved?

A simple example might be two images which, in portrait, are stacked one above the other, but in landscape are side-by-side.

If this is not possible, how else might I accomplish this layout?

I am constructing my views and constraints in code and not using interface builder.

like image 418
Ben Packard Avatar asked Jul 21 '13 13:07

Ben Packard


People also ask

What is the use of Autolayout?

Auto layout is a property you can add to frames and components. It lets you create designs that grow to fill or shrink to fit, and reflow as their contents change. This is great when you need to add new layers, accommodate longer text strings, or maintain alignment as your designs evolve.

What are two properties that auto layout constraints control on a Uiview?

Auto Layout defines margins for each view. These margins describe the preferred spacing between the edge of the view and its subviews. You can access the view's margins using either the layoutMargins or layoutMarginsGuide property. The layoutMargins property lets you get and set the margins as a UIEdgeInsets structure.

What are auto layout constraints?

Auto Layout constraints allow us to create views that dynamically adjust to different size classes and positions. The constraints will make sure that your views adjust to any size changes without having to manually update frames or positions.

What is multiplier in Autolayout?

The multiplier which is represented as M in the equation is use to multiply (adjust) the relation by a certain of floating point value. We can say viewA. height should be *2 (two times) of viewB.


1 Answers

Edit: Using the new concept of Size Classes introduced in Xcode 6, you can easily setup different constraints for specific size classes in Interface Builder. Most devices (e.g. all current iPhones) have a Compact vertical size class in landscape mode.

This is a much better concept for general layout decisions than determining the device's orientation.

That being said, if you really need to know the orientation, UIDevice.currentDevice().orientation is the way to go.


Original post:

Override the updateViewConstraints method of UIViewController to provide layout constraints for specific situations. This way, the layout is always set up the correct way according to situation. Make sure they form a complete set of constraints with those created within the storyboard. You can use IB to set up your general constraints and mark those subject to change to be removed at runtime.

I use the following implementation to present a different set of constraints for each orientation:

-(void)updateViewConstraints {     [super updateViewConstraints];      // constraints for portrait orientation     // use a property to change a constraint's constant and/or create constraints programmatically, e.g.:     if (!self.layoutConstraintsPortrait) {         UIView *image1 = self.image1;         UIView *image2 = self.image2;         self.layoutConstraintsPortrait = [[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[image1]-[image2]-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(image1, image2)] mutableCopy];         [self.layoutConstraintsPortrait addObject:[NSLayoutConstraint constraintWithItem:image1 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem: image1.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];         [self.layoutConstraintsPortrait addObject:[NSLayoutConstraint constraintWithItem:image2 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:image2.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];     }      // constraints for landscape orientation     // make sure they don't conflict with and complement the existing constraints     if (!self.layoutConstraintsLandscape) {         UIView *image1 = self.image1;         UIView *image2 = self.image2;         self.layoutConstraintsLandscape = [[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[image1]-[image2]-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(image1, image2)] mutableCopy];         [self.layoutConstraintsLandscape addObject:[NSLayoutConstraint constraintWithItem:image1 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:image1.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];         [self.layoutConstraintsLandscape addObject:[NSLayoutConstraint constraintWithItem:image2 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem: image2.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];     }      BOOL isPortrait = UIInterfaceOrientationIsPortrait(self.interfaceOrientation);     [self.view removeConstraints:isPortrait ? self.layoutConstraintsLandscape : self.layoutConstraintsPortrait];     [self.view addConstraints:isPortrait ? self.layoutConstraintsPortrait : self.layoutConstraintsLandscape];         } 

Now, all you need to do is trigger a constraint update whenever the situation changes. Override willAnimateRotationToInterfaceOrientation:duration: to animate the constraint update on orientation change:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {     [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];      [self.view setNeedsUpdateConstraints];  } 
like image 92
knl Avatar answered Sep 24 '22 05:09

knl