What good is a static layout? When specifying layout using constraints, we still need to provide transitions and other animations in our interfaces. We can do this quite easily by just animating between different sets of constraints.
Episode Links Episode Source Code Animating the Left View We need some properties to be able to re-generate constraints when the animation occurs: @property (nonatomic, strong) NSLayoutConstraint *leftWidthConstraint; @property (nonatomic, strong) UIView *leftView; @property (nonatomic, strong) UIView *headlineView; @property (nonatomic) BOOL expanded; Then we extract a method that can define our left view constraints given a passed in width: - (NSLayoutConstraint *)leftWidthConstraintWithMultiplier:(CGFloat)multiplier { return [NSLayoutConstraint constraintWithItem:self.leftView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.headlineView attribute:NSLayoutAttributeWidth multiplier:multiplier constant:0]; } And then set up the initial state in viewDidLoad: self.leftWidthConstraint = [self leftWidthConstraintWithMultiplier:0.3]; [self.view addConstraint:self.leftWidthConstraint]; Then, when the button is tapped: - (void)onButtonTap:(id)sender { CGFloat multiplier = self.expanded ? 0.3 : 0.7; self.expanded = !self.expanded; [self.view removeConstraint:self.leftWidthConstraint]; self.leftWidthConstraint = [self leftWidthConstraintWithMultiplier:multiplier]; [self.view addConstraint:self.leftWidthConstraint]; [UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:4 options:0 animations:^{ [self.view layoutIfNeeded]; } completion:nil]; } Note that we simply animate the layoutIfNeeded method call. Changing the constraints doesn't immediately change any layout, allowing you to be temporarily in an inconsistent state while you build up the necessary constraints to fully specify the layout. Then when you are ready, you call layoutIfNeeded. Animating in the Accessory View We're going to do a similar thing for the accessory view. Starting with some extra properties we'll need: @property (nonatomic, strong) UIView *accessoryView; @property (nonatomic, strong) NSArray *verticalConstraints; @property (nonatomic) BOOL accessoryVisible Then we create a function that will return our vertical constraints: - (NSArray *)verticalConstraintsWithAccessoryViewVisible:(BOOL)visible { NSDictionary *metrics = @{ @"topPadding": visible ? @40 : @60, @"headlineViewHeight": visible ? @80 : @100, @"accessoryPadding": visible ? @8 : @0, @"accessoryHeight" : visible ? @100 : @0 }; return [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(topPadding)-[_headlineView(headlineViewHeight)]-[_leftView]-(accessoryPadding)-[_accessoryView(accessoryHeight)]-|" options:NSLayoutFormatAlignAllLeft metrics:metrics views:NSDictionaryOfVariableBindings(_headlineView, _leftView, _accessoryView)]; } Notice that we have a zero height padding and view if the view is invisible. We can set the initial state in viewDidLoad: self.verticalConstraints = [self verticalConstraintsWithAccessoryViewVisible:NO]; [self.view addConstraints:self.verticalConstraints]; Then when we tap on the left view: - (void)onLeftViewTap:(id)sender { self.accessoryVisible = !self.accessoryVisible; [self.view removeConstraints:self.verticalConstraints]; self.verticalConstraints = [self verticalConstraintsWithAccessoryViewVisible:self.accessoryVisible]; [self.view addConstraints:self.verticalConstraints]; [UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:4 options:0 animations:^{ [self.view layoutIfNeeded]; } completion:nil]; }