2

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?

Amal T S
  • 3,327
  • 2
  • 24
  • 57
  • 1
    "It is not working" in what way? Do all animate at once? Do none animate? Does only the first animate? Please elaborate. – Stonz2 Jul 30 '20 at 18:08
  • @Stonz2 I have updated the question. Only the first one is animating now – Amal T S Jul 30 '20 at 18:10
  • could you add a log in each completion to see what is happening ? Note, that is not exactly a Swift topic, but no matter. – claude31 Jul 30 '20 at 18:48
  • Does this answer your question? [Change UIView constraints in chained animations](https://stackoverflow.com/questions/49362866/change-uiview-constraints-in-chained-animations) – Stonz2 Jul 30 '20 at 19:32

2 Answers2

4

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

Rob
  • 415,655
  • 72
  • 787
  • 1,044
1

It would help if you showed all your code (how you setup the constraints, etc).

But, here is a quick example.

It creates 6 labels, with top constraints at 100. Tap the "Do Anim" button to animated them to Top: 0.0 ... tap again to animate back to 100:

#import "SequentialAnimViewController.h"

@interface SequentialAnimViewController () {
    NSMutableArray *views;
    NSMutableArray *topConstraints;
}
@end

@implementation SequentialAnimViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
    [button addTarget:self action:@selector(animViews) forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"Do Anim" forState:UIControlStateNormal];
    button.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1.0];
    button.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:button];
    
    [button.centerXAnchor constraintEqualToAnchor:[self.view centerXAnchor]].active = YES;
    [button.centerYAnchor constraintEqualToAnchor:[self.view centerYAnchor]].active = YES;
    [button.widthAnchor constraintEqualToConstant:200.0].active = YES;

    views = [NSMutableArray new];
    topConstraints = [NSMutableArray new];
    
    CGFloat x = 40.0;
    CGFloat w = 40.0;

    UILayoutGuide *g = [self.view safeAreaLayoutGuide];

    for (int i = 0; i < 6; i++) {
        UILabel *v = [UILabel new];
        v.backgroundColor = [UIColor blueColor];
        v.textColor = [UIColor yellowColor];
        v.textAlignment = NSTextAlignmentCenter;
        v.text = [NSString stringWithFormat:@"%i", i];
        v.translatesAutoresizingMaskIntoConstraints = NO;

        [self.view addSubview:v];
        [v.widthAnchor constraintEqualToConstant:w].active = YES;
        [v.heightAnchor constraintEqualToConstant:w].active = YES;
        [v.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:x].active = YES;

        [topConstraints addObject:[v.topAnchor constraintEqualToAnchor:g.topAnchor constant:100.0]];
        [views addObject:v];

        x += w + 8;
    }
    
    [NSLayoutConstraint activateConstraints:topConstraints];
}

-(void)animViews {
    __block int i = 0;
    __block CGFloat newConstant = ((NSLayoutConstraint *)self->topConstraints[0]).constant == 0.0 ? 100.0 : 0.0;
    ((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
    [UIView animateWithDuration:1.0 animations:^{
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {
        ((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
        [UIView animateWithDuration:1.0 animations:^{
            [self.view layoutIfNeeded];
        } completion:^(BOOL finished) {
            ((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
            [UIView animateWithDuration:1.0 animations:^{
                [self.view layoutIfNeeded];
            } completion:^(BOOL finished) {
                ((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
                [UIView animateWithDuration:1.0 animations:^{
                    [self.view layoutIfNeeded];
                } completion:^(BOOL finished) {
                    ((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
                    [UIView animateWithDuration:1.0 animations:^{
                        [self.view layoutIfNeeded];
                    } completion:^(BOOL finished) {
                        ((NSLayoutConstraint *)self->topConstraints[i++]).constant = newConstant;
                        [UIView animateWithDuration:1.0 animations:^{
                            [self.view layoutIfNeeded];
                        } completion:^(BOOL finished) {
                            NSLog(@"All Done!");
                        }];
                    }];
                }];
            }];
        }];
    }];
}
@end
DonMag
  • 69,424
  • 5
  • 50
  • 86