Search code examples
iosobjective-cswiftnslayoutconstraintuiviewanimationtransition

How to animate constraints one by one in IOS?


I have 6 views. I want to animate the constraints one by one, ie, i need the animation on second view only after first, then after second the third and so on. I have added the code in the completion handler of the animations, but it is not working. initial value of all the constraint is set to 300 in storyboard. I want to change it to 0 one by one. Now, only the first animation is working. This is what i have done.

layoutTopFirst.constant = 0.0;
    [UIView animateWithDuration:1.0 animations:^{
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {
        self->layoutTopSecond.constant = 0.0;
        [UIView animateWithDuration:1.0 animations:^{
            [self.view layoutIfNeeded];
        } completion:^(BOOL finished) {
            self->layoutTopThird.constant = 0.0;
            [UIView animateWithDuration:1.0 animations:^{
                [self.view layoutIfNeeded];
            } completion:^(BOOL finished) {
                self->layoutTopFourth.constant = 0.0;
                [UIView animateWithDuration:1.0 animations:^{
                    [self.view layoutIfNeeded];
                } completion:^(BOOL finished) {
                    self->layoutTopFifth.constant = 0.0;
                    [UIView animateWithDuration:1.0 animations:^{
                        [self.view layoutIfNeeded];
                    } completion:^(BOOL finished) {
                        self->layoutTopSixth.constant = 0.0;
                        [UIView animateWithDuration:1.0 animations:^{
                            [self.view layoutIfNeeded];
                        } completion:^(BOOL finished) {
                            
                        }];
                    }];
                }];
            }];
        }];
    }];

How to do animations one after another?


Solution

  • If only the first one is animating, make sure that

    • your other five constraint references all point to different vertical constraints ... if they were nil for example, you won't see any changes;
    • that they're all isActive;
    • that there aren't any other constraints that are preventing the updated constants from yielding changes.

    For what it's worth, you might consider eliminating your tower of completion handlers with keyframe animation, e.g.

    CGFloat relativeDuration = 1.0 / 6.0;
    
    [UIView animateKeyframesWithDuration:6 delay:0 options:kNilOptions animations:^{
        [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:relativeDuration animations:^{
            self.topConstraint1.constant = 0;
            [self.view layoutIfNeeded];
        }];
    
        [UIView addKeyframeWithRelativeStartTime:1.0 * relativeDuration relativeDuration:relativeDuration animations:^{
            self.topConstraint2.constant = 0;
            [self.view layoutIfNeeded];
        }];
    
        [UIView addKeyframeWithRelativeStartTime:2.0 * relativeDuration relativeDuration:relativeDuration animations:^{
            self.topConstraint3.constant = 0;
            [self.view layoutIfNeeded];
        }];
    
        [UIView addKeyframeWithRelativeStartTime:3.0 * relativeDuration relativeDuration:relativeDuration animations:^{
            self.topConstraint4.constant = 0;
            [self.view layoutIfNeeded];
        }];
    
        [UIView addKeyframeWithRelativeStartTime:4.0 * relativeDuration relativeDuration:relativeDuration animations:^{
            self.topConstraint5.constant = 0;
            [self.view layoutIfNeeded];
        }];
    
        [UIView addKeyframeWithRelativeStartTime:5.0 * relativeDuration relativeDuration:relativeDuration animations:^{
            self.topConstraint6.constant = 0;
            [self.view layoutIfNeeded];
        }];
    } completion:nil];
    

    Or, even simpler:

    NSArray <NSLayoutConstraint *> *constraints = @[self.topConstraint1, self.topConstraint2, self.topConstraint3, self.topConstraint4, self.topConstraint5, self.topConstraint6];
    
    CGFloat relativeDuration = 1.0 / (CGFloat) constraints.count;
    
    [UIView animateKeyframesWithDuration:totalDuration delay:0 options:kNilOptions animations:^{
        for (NSInteger i = 0; i < constraints.count; i++) {
            [UIView addKeyframeWithRelativeStartTime: ((CGFloat) i) * relativeDuration relativeDuration:relativeDuration animations:^{
                constraints[i].constant = 0;
                [self.view layoutIfNeeded];
            }];
        }
    } completion:nil];
    

    That yields:

    enter image description here