How do I animate constraint changes?
Asked Answered
A

12

1049

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.

Ambiversion answered 27/9, 2012 at 13:23 Comment(0)
C
1813

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()
}
Crossexamine answered 30/9, 2012 at 19:0 Comment(24)
You have tried doing the change in the constant and layoutIfNeeded both inside the animation block, right?Crossexamine
yes, I've tried that. I had it that way originally and only modified after a second watch on the WWDC video.Ambiversion
There are no other constraint changes. The constraints on the ad banner are distance from left edge(0), distance from right edge(0), fixed height(32) and distance from bottom(0). There are no other constraints associated with the banner. Commenting out the constraint change will means nothing occurs.Ambiversion
You know what... your answer works. The WWDC works.... my vision fails. For some reason it took me a week to realize I was calling setNeedsLayout instead of layoutIfNeeded. I'm slightly horrified by how many hours I spent not noticing I just just typed the wrong method name.Ambiversion
The solution works but you don't need to change the constraint constant within the animation block. It's totally fine to set the constraint once before kicking off the animation. You should edit your answer.Magree
This didn't work for me initially and then I realized you need to call layoutIfNeeded on the PARENT view, not the view the constraints apply to.Quarrel
using layoutIfNeeded will animate all the subview refreshes not just the constraint change. how do u animate the constraint change only?Odrick
works great - thanks. but just so we're clear: it is pure insanity for constraints to basically exist in an entirely different scope for animation. this really guts some very clean older animation logic.Selfloading
I couldnt get this to working, thinking i had to call layoutIfNeeded on the parent view of the constraint. I changed it to the parent view of the view controller and now its works beautifullyHardboiled
Also be careful with UILabels. Some type animation with UILabel works differently against the same code with simple UIView . Unfortunately, I don't know why. And if someone knows about it I really appreciate to comment me.Ellanellard
This works perfectly and I'd like to note I'm calling layoutIfNeeded on the subview, not it's parent view. Not really sure why are others are having to call it on the parent.Mehetabel
"Apple actually recommends you call it once before the animation block to ensure that all pending layout operations have been completed", thank you, never thought about that, but it makes sense.Alessandro
I liked this but wanted the EaseIn effect, and found this works nicely in Swift: UIView.animateWithDuration(0.3, delay: 0, options: UIViewAnimationOptions.CurveEaseIn, animations: { self.view.layoutIfNeeded() }, completion: nil)Wag
This does not work with related constraints. Let's say we animate a height A with this, height B that is dependent on height A will be shorter when height A is long, and longer when height A is short. B will unfortunately change right away and will NOT animate.Euripus
Sometimes the animation don't animate and run straight to completion. How to solve it?Strongbox
I've implemented your solution multiple times successfully, today it wouldn't work for a new implementation. Found out you need to call self.view.layoutIfNeeded() in the animation block, NOT the completion block. Doh!Metallist
The "Apple actually recommends" link is broken. If someone knows the new URL can they please update?Delouse
Code example would look better if in the callback one would call [subview.superview layoutIfNeeded];Sift
@Odrick Setup all constraint you don't want to animate -> call layoutIfNeeded and then setup animation block with that one constraint you want to animate, another layoutIfNeeded included.Mima
Yes, it works on iOS 11 beta5, and dont need to update the constraint inside animation block.Halogenate
Initially it didn't worked for me but then I realised that I've to put isHidden = false out of the animation block and inside the completion block insteadGrundyism
I'm confused about the manner of updating constraints and wrote this. Can you please take a look?Jeanajeanbaptiste
that's not correct. Constraints should be updated outside of the animation block and inside the animation block you should have only view.layoutIfNeeded()Hydrastine
Still works on iOS 16.3, I do wonder however when Apple will be adding the possibility to change constraint multipliers as well...Resurrectionist
S
117

I appreciate the answer provided, but I think it would be nice to take it a bit further.

The basic block animation from the documentation

[containerView layoutIfNeeded]; // Ensures that all pending layout operations have been completed
[UIView animateWithDuration:1.0 animations:^{
     // Make all constraint changes here
     [containerView layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes
}];

but really this is a very simplistic scenario. What if I want to animate subview constraints via the updateConstraints method?

An animation block that calls the subviews updateConstraints method

[self.view layoutIfNeeded];
[self.subView setNeedsUpdateConstraints];
[self.subView updateConstraintsIfNeeded];
[UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionLayoutSubviews animations:^{
    [self.view layoutIfNeeded];
} completion:nil];

The updateConstraints method is overridden in the UIView subclass and must call super at the end of the method.

- (void)updateConstraints
{
    // Update some constraints

    [super updateConstraints];
}

The AutoLayout Guide leaves much to be desired but it is worth reading. I myself am using this as part of a UISwitch that toggles a subview with a pair of UITextFields with a simple and subtle collapse animation (0.2 seconds long). The constraints for the subview are being handled in the UIView subclasses updateConstraints methods as described above.

Sherri answered 22/1, 2014 at 0:35 Comment(6)
When calling all the methods above on self.view (and not on a subview of that view), calling updateConstraintsIfNeeded is not necessary (because setNeedsLayout also triggers updateConstraints of that view). Might be trivial for the most, but it was not for me until now ;)Limpkin
It is hard to comment without knowing the full interplay of Autolayout and springs and struts layout in your particular case. I'm speaking entirely about a pure autolayout scenario. I would be curious to know what exactly is happening in your layoutSubviews method.Sherri
translatesAutoresizingMaskIntoConstraints = NO; If you want to pure-autolayout you should definitely disable this.Sherri
I haven't seen that, but I can't really speak to the issue without some code. Maybe you could mock up a TableView and stick it on GitHub?Sherri
Beware: If using the UIViewAnimationOptionBeginFromCurrentState the layout constraints will be set BEFORE the animation!Saltatory
I'm confused about the manner of updating constraints and wrote this. Can you please take a look?Jeanajeanbaptiste
O
85

Generally, you just need to update constraints and call layoutIfNeeded inside the animation block. This can be either changing the .constant property of an NSLayoutConstraint, adding remove constraints (iOS 7), or changing the .active property of constraints (iOS 8 & 9).

Sample Code:

[UIView animateWithDuration:0.3 animations:^{
    // Move to right
    self.leadingConstraint.active = false;
    self.trailingConstraint.active = true;

    // Move to bottom
    self.topConstraint.active = false;
    self.bottomConstraint.active = true;

    // Make the animation happen
    [self.view setNeedsLayout];
    [self.view layoutIfNeeded];
}];

Sample Setup:

Xcode Project so sample animation project.

Controversy

There are some questions about whether the constraint should be changed before the animation block, or inside it (see previous answers).

The following is a Twitter conversation between Martin Pilkington who teaches iOS, and Ken Ferry who wrote Auto Layout. Ken explains that though changing constants outside of the animation block may currently work, it's not safe and they should really be change inside the animation block. https://twitter.com/kongtomorrow/status/440627401018466305

Animation:

Sample Project

Here's a simple project showing how a view can be animated. It's using Objective C and animates the view by changing the .active property of several constraints. https://github.com/shepting/SampleAutoLayoutAnimation

Ornithology answered 13/11, 2015 at 0:33 Comment(6)
+1 for showing an example using the new active flag. Also, changing the constraint outside the animation block always felt like a hack to meVibrato
I raised an issue in github because this solution doesn't work for moving the view back to where it was. I believe changing active isn't the correct solution and you should be changing the priority instead. Set the top to 750, and the bottom to 250, then in code alternate between UILayoutPriorityDefaultHigh and UILayoutPriorityDefaultLow.Avruch
Another reason for updating inside the block is that it isolates the changes from calling code that may happen to also call layoutIfNeeded. (and thanks for the Twitter link)Burdick
Great answer. Specially because you mention Martin's and Ken's conversation about this.Cimbura
I'm confused about the manner of updating constraints and wrote this. Can you please take a look?Jeanajeanbaptiste
that's not correct. Constraints should be updated outside of the animation block and inside the animation block you should have only view.layoutIfNeeded()Hydrastine
C
40
// Step 1, update your constraint
self.myOutletToConstraint.constant = 50; // New height (for example)

// Step 2, trigger animation
[UIView animateWithDuration:2.0 animations:^{

    // Step 3, call layoutIfNeeded on your animated view's parent
    [self.view layoutIfNeeded];
}];
Corrinacorrine answered 23/12, 2013 at 14:29 Comment(0)
C
33

Swift 4 solution

UIView.animate

Three simple steps:

  1. Change the constraints, e.g.:

    heightAnchor.constant = 50
    
  2. Tell the containing view that its layout is dirty and that the autolayout should recalculate the layout:

    self.view.setNeedsLayout()
    
  3. In animation block tell the layout to recalculate the layout, which is equivalent of setting the frames directly (in this case the autolayout will set the frames):

    UIView.animate(withDuration: 0.5) {
        self.view.layoutIfNeeded()
    }
    

Complete simplest example:

heightAnchor.constant = 50
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.5) {
    self.view.layoutIfNeeded()
}

Sidenote

There is an optional 0th step - before changing the constraints you might want to call self.view.layoutIfNeeded() to make sure that the starting point for the animation is from the state with old constraints applied (in case there were some other constraints changes that should not be included in animation):

otherConstraint.constant = 30
// this will make sure that otherConstraint won't be animated but will take effect immediately
self.view.layoutIfNeeded()

heightAnchor.constant = 50
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.5) {
    self.view.layoutIfNeeded()
}

UIViewPropertyAnimator

Since with iOS 10 we got a new animating mechanism - UIViewPropertyAnimator, we should know that basically the same mechanism applies to it. The steps are basically the same:

heightAnchor.constant = 50
self.view.setNeedsLayout()
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UICubicTimingParameters(animationCurve: .linear))
animator.addAnimations {
    self.view.layoutIfNeeded()
}
animator.startAnimation()

Since animator is an encapsulation of the animation, we can keep reference to it and call it later. However, since in the animation block we just tell the autolayout to recalculate the frames, we have to change the constraints before calling startAnimation. Therefore something like this is possible:

// prepare the animator first and keep a reference to it
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UICubicTimingParameters(animationCurve: .linear))
animator.addAnimations {
    self.view.layoutIfNeeded()
}

// at some other point in time we change the constraints and call the animator
heightAnchor.constant = 50
self.view.setNeedsLayout()
animator.startAnimation()

The order of changing constraints and starting an animator is important - if we just change the constraints and leave our animator for some later point, the next redraw cycle can invoke autolayout recalculation and the change will not be animated.

Also, remember that a single animator is non-reusable - once you run it, you cannot "rerun" it. So I guess there is not really a good reason to keep the animator around, unless we use it for controlling an interactive animation.

Christabelle answered 16/2, 2018 at 11:9 Comment(1)
layoutIfNeeded() is the keyChainey
T
19

Swift solution:

yourConstraint.constant = 50
UIView.animate(withDuration: 1.0, animations: {
    yourView.layoutIfNeeded
})
Teach answered 11/8, 2016 at 8:42 Comment(0)
B
16

Storyboard, Code, Tips and a few Gotchas

The other answers are just fine but this one highlights a few fairly important gotchas of animating constraints using a recent example. I went through a lot of variations before I realized the following:

Make the constraints you want to target into Class variables to hold a strong reference. In Swift I used lazy variables:

lazy var centerYInflection:NSLayoutConstraint = {
       let temp =  self.view.constraints.filter({ $0.firstItem is MNGStarRating }).filter ( { $0.secondItem is UIWebView }).filter({ $0.firstAttribute == .CenterY }).first
        return temp!
}()

After some experimentation I noted that one MUST obtain the constraint from the view ABOVE (aka the superview) the two views where the constraint is defined. In the example below (both MNGStarRating and UIWebView are the two types of items I am creating a constraint between, and they are subviews within self.view).

Filter Chaining

I take advantage of Swift's filter method to separate the desired constraint that will serve as the inflection point. One could also get much more complicated but filter does a nice job here.

Animating Constraints Using Swift

Nota Bene - This example is the storyboard/code solution and assumes one has made default constraints in the storyboard. One can then animate the changes using code.

Assuming you create a property to filter with accurate criteria and get to a specific inflection point for your animation (of course you could also filter for an array and loop through if you need multiple constraints):

lazy var centerYInflection:NSLayoutConstraint = {
    let temp =  self.view.constraints.filter({ $0.firstItem is MNGStarRating }).filter ( { $0.secondItem is UIWebView }).filter({ $0.firstAttribute == .CenterY }).first
    return temp!
}()

....

Sometime later...

@IBAction func toggleRatingView (sender:AnyObject){

    let aPointAboveScene = -(max(UIScreen.mainScreen().bounds.width,UIScreen.mainScreen().bounds.height) * 2.0)

    self.view.layoutIfNeeded()


    //Use any animation you want, I like the bounce in springVelocity...
    UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.75, options: [.CurveEaseOut], animations: { () -> Void in

        //I use the frames to determine if the view is on-screen
        if CGRectContainsRect(self.view.frame, self.ratingView.frame) {

            //in frame ~ animate away
            //I play a sound to give the animation some life

            self.centerYInflection.constant = aPointAboveScene
            self.centerYInflection.priority = UILayoutPriority(950)

        } else {

            //I play a different sound just to keep the user engaged
            //out of frame ~ animate into scene
            self.centerYInflection.constant = 0
            self.centerYInflection.priority = UILayoutPriority(950)
            self.view.setNeedsLayout()
            self.view.layoutIfNeeded()
         }) { (success) -> Void in

            //do something else

        }
    }
}

The many wrong turns

These notes are really a set of tips that I wrote for myself. I did all the don'ts personally and painfully. Hopefully this guide can spare others.

  1. Watch out for zPositioning. Sometimes when nothing is apparently happening, you should hide some of the other views or use the view debugger to locate your animated view. I've even found cases where a User Defined Runtime Attribute was lost in a storyboard's xml and led to the animated view being covered (while working).

  2. Always take a minute to read the documentation (new and old), Quick Help, and headers. Apple keeps making a lot of changes to better manage AutoLayout constraints (see stack views). Or at least the AutoLayout Cookbook. Keep in mind that sometimes the best solutions are in the older documentation/videos.

  3. Play around with the values in the animation and consider using other animateWithDuration variants.

  4. Don't hardcode specific layout values as criteria for determining changes to other constants, instead use values that allow you to determine the location of the view. CGRectContainsRect is one example

  5. If needed, don't hesitate to use the layout margins associated with a view participating in the constraint definition let viewMargins = self.webview.layoutMarginsGuide: is on example
  6. Don't do work you don't have to do, all views with constraints on the storyboard have constraints attached to the property self.viewName.constraints
  7. Change your priorities for any constraints to less than 1000. I set mine to 250 (low) or 750 (high) on the storyboard; (if you try to change a 1000 priority to anything in code then the app will crash because 1000 is required)
  8. Consider not immediately trying to use activateConstraints and deactivateConstraints (they have their place but when just learning or if you are using a storyboard using these probably means your doing too much ~ they do have a place though as seen below)
  9. Consider not using addConstraints / removeConstraints unless you are really adding a new constraint in code. I found that most times I layout the views in the storyboard with desired constraints (placing the view offscreen), then in code, I animate the constraints previously created in the storyboard to move the view around.
  10. I spent a lot of wasted time building up constraints with the new NSAnchorLayout class and subclasses. These work just fine but it took me a while to realize that all the constraints that I needed already existed in the storyboard. If you build constraints in code then most certainly use this method to aggregate your constraints:

Quick Sample Of Solutions to AVOID when using Storyboards

private var _nc:[NSLayoutConstraint] = []
    lazy var newConstraints:[NSLayoutConstraint] = {

        if !(self._nc.isEmpty) {
            return self._nc
        }

        let viewMargins = self.webview.layoutMarginsGuide
        let minimumScreenWidth = min(UIScreen.mainScreen().bounds.width,UIScreen.mainScreen().bounds.height)

        let centerY = self.ratingView.centerYAnchor.constraintEqualToAnchor(self.webview.centerYAnchor)
        centerY.constant = -1000.0
        centerY.priority = (950)
        let centerX =  self.ratingView.centerXAnchor.constraintEqualToAnchor(self.webview.centerXAnchor)
        centerX.priority = (950)

        if let buttonConstraints = self.originalRatingViewConstraints?.filter({

            ($0.firstItem is UIButton || $0.secondItem is UIButton )
        }) {
            self._nc.appendContentsOf(buttonConstraints)

        }

        self._nc.append( centerY)
        self._nc.append( centerX)

        self._nc.append (self.ratingView.leadingAnchor.constraintEqualToAnchor(viewMargins.leadingAnchor, constant: 10.0))
        self._nc.append (self.ratingView.trailingAnchor.constraintEqualToAnchor(viewMargins.trailingAnchor, constant: 10.0))
        self._nc.append (self.ratingView.widthAnchor.constraintEqualToConstant((minimumScreenWidth - 20.0)))
        self._nc.append (self.ratingView.heightAnchor.constraintEqualToConstant(200.0))

        return self._nc
    }()

If you forget one of these tips or the more simple ones such as where to add the layoutIfNeeded, most likely nothing will happen: In which case you may have a half baked solution like this:

NB - Take a moment to read the AutoLayout Section Below and the original guide. There is a way to use these techniques to supplement your Dynamic Animators.

UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 1.0, options: [.CurveEaseOut], animations: { () -> Void in

            //
            if self.starTopInflectionPoint.constant < 0  {
                //-3000
                //offscreen
                self.starTopInflectionPoint.constant = self.navigationController?.navigationBar.bounds.height ?? 0
                self.changeConstraintPriority([self.starTopInflectionPoint], value: UILayoutPriority(950), forView: self.ratingView)

            } else {

                self.starTopInflectionPoint.constant = -3000
                 self.changeConstraintPriority([self.starTopInflectionPoint], value: UILayoutPriority(950), forView: self.ratingView)
            }

        }) { (success) -> Void in

            //do something else
        }

    }

Snippet from the AutoLayout Guide (note the second snippet is for using OS X). BTW - This is no longer in the current guide as far as I can see. The preferred techniques continue to evolve.

Animating Changes Made by Auto Layout

If you need full control over animating changes made by Auto Layout, you must make your constraint changes programmatically. The basic concept is the same for both iOS and OS X, but there are a few minor differences.

In an iOS app, your code would look something like the following:

[containerView layoutIfNeeded]; // Ensures that all pending layout operations have been completed
[UIView animateWithDuration:1.0 animations:^{
     // Make all constraint changes here
     [containerView layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes
}];

In OS X, use the following code when using layer-backed animations:

[containterView layoutSubtreeIfNeeded];
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
     [context setAllowsImplicitAnimation: YES];
     // Make all constraint changes here
     [containerView layoutSubtreeIfNeeded];
}];

When you aren’t using layer-backed animations, you must animate the constant using the constraint’s animator:

[[constraint animator] setConstant:42];

For those who learn better visually check out this early video from Apple.

Pay Close Attention

Often in documentation there are small notes or pieces of code that lead to bigger ideas. For example attaching auto layout constraints to dynamic animators is a big idea.

Good Luck and May the Force be with you.

Baffle answered 11/12, 2015 at 1:49 Comment(0)
T
14

Working Solution 100% Swift 5.3

i have read all the answers and want to share the code and hierarchy of lines which i have used in all my applications to animate them correctly, Some solutions here are not working, you should check them on slower devices e.g iPhone 5 at this moment.

self.btnHeightConstraint.constant = 110
UIView.animate(withDuration: 0.27) { [weak self] in 
     self?.view.layoutIfNeeded()
}
Toothless answered 12/6, 2017 at 8:41 Comment(0)
P
5

I was trying to animate Constraints and was not really easy to found a good explanation.

What other answers are saying is totally true: you need to call [self.view layoutIfNeeded]; inside animateWithDuration: animations:. However, the other important point is to have pointers for every NSLayoutConstraint you want to animate.

I created an example in GitHub.

Peckham answered 25/11, 2014 at 8:24 Comment(0)
V
4

Working and just tested solution for Swift 3 with Xcode 8.3.3:

self.view.layoutIfNeeded()
self.calendarViewHeight.constant = 56.0

UIView.animate(withDuration: 0.5, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
        self.view.layoutIfNeeded()
    }, completion: nil)

Just keep in mind that self.calendarViewHeight is a constraint referred to a customView (CalendarView). I called the .layoutIfNeeded() on self.view and NOT on self.calendarView

Hope this help.

Virgate answered 19/7, 2017 at 12:17 Comment(0)
B
3

There is an article talk about this: http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was

In which, he coded like this:

- (void)handleTapFrom:(UIGestureRecognizer *)gesture {
    if (_isVisible) {
        _isVisible = NO;
        self.topConstraint.constant = -44.;    // 1
        [self.navbar setNeedsUpdateConstraints];  // 2
        [UIView animateWithDuration:.3 animations:^{
            [self.navbar layoutIfNeeded]; // 3
        }];
    } else {
        _isVisible = YES;
        self.topConstraint.constant = 0.;
        [self.navbar setNeedsUpdateConstraints];
        [UIView animateWithDuration:.3 animations:^{
            [self.navbar layoutIfNeeded];
        }];
    }
}

Hope it helps.

Brake answered 13/9, 2013 at 8:35 Comment(0)
D
1

In the context of constraint animation, I would like to mention a specific situation where I animated a constraint immediately within a keyboard_opened notification.

Constraint defined a top space from a textfield to top of the container. Upon keyboard opening, I just divide the constant by 2.

I was unable to achieve a conistent smooth constraint animation directly within the keyboard notification. About half the times view would just jump to its new position - without animating.

It occured to me there might be some additional layouting happening as result of keyboard opening. Adding a simple dispatch_after block with a 10ms delay made the animation run every time - no jumping.

Destination answered 15/4, 2016 at 15:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.