Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I animate constraint changes?

I'm updating an old app with an AdBannerView and when there is no ad, it slides off screen. When there is an ad it slides on the screen. Basic stuff.

Old style, I set the frame in an animation block. New style, I have a IBOutlet to the auto-layout constraint which determines the Y position, in this case it's distance from the bottom of the superview, and modify the constant:

- (void)moveBannerOffScreen {     [UIView animateWithDuration:5 animations:^{         _addBannerDistanceFromBottomConstraint.constant = -32;     }];     bannerIsVisible = FALSE; }  - (void)moveBannerOnScreen {     [UIView animateWithDuration:5 animations:^{         _addBannerDistanceFromBottomConstraint.constant = 0;     }];     bannerIsVisible = TRUE; } 

And the banner moves, exactly as expected, but no animation.


UPDATE: I re-watched WWDC 12 talk Best Practices for Mastering Auto Layout which covers animation. It discusses how to update constraints using CoreAnimation:

I've tried with the following code, but get the exact same results:

- (void)moveBannerOffScreen {     _addBannerDistanceFromBottomConstraint.constant = -32;     [UIView animateWithDuration:2 animations:^{         [self.view setNeedsLayout];     }];     bannerIsVisible = FALSE; }  - (void)moveBannerOnScreen {     _addBannerDistanceFromBottomConstraint.constant = 0;     [UIView animateWithDuration:2 animations:^{         [self.view setNeedsLayout];     }];     bannerIsVisible = TRUE; } 

On a side note, I have checked numerous times and this is being executed on the main thread.

like image 663
DBD Avatar asked Sep 27 '12 13:09

DBD


People also ask

What is a constraint in animation?

An animation constraint is a special type of controller that can help you automate the animation process. You can use constraints to control an object's position, rotation, or scale through a binding relationship with another object. A constraint requires an animated object and at least one target object.


1 Answers

Two important notes:

  1. You need to call layoutIfNeeded within the animation block. Apple actually recommends you call it once before the animation block to ensure that all pending layout operations have been completed

  2. You need to call it specifically on the parent view (e.g. self.view), not the child view that has the constraints attached to it. Doing so will update all constrained views, including animating other views that might be constrained to the view that you changed the constraint of (e.g. View B is attached to the bottom of View A and you just changed View A's top offset and you want View B to animate with it)

Try this:

Objective-C

- (void)moveBannerOffScreen {     [self.view layoutIfNeeded];      [UIView animateWithDuration:5         animations:^{             self._addBannerDistanceFromBottomConstraint.constant = -32;             [self.view layoutIfNeeded]; // Called on parent view         }];     bannerIsVisible = FALSE; }  - (void)moveBannerOnScreen {      [self.view layoutIfNeeded];      [UIView animateWithDuration:5         animations:^{             self._addBannerDistanceFromBottomConstraint.constant = 0;             [self.view layoutIfNeeded]; // Called on parent view         }];     bannerIsVisible = TRUE; } 

Swift 3

UIView.animate(withDuration: 5) {     self._addBannerDistanceFromBottomConstraint.constant = 0     self.view.layoutIfNeeded() } 
like image 167
g3rv4 Avatar answered Sep 21 '22 11:09

g3rv4