Amal T S
Amal T S

Reputation: 3405

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?

Upvotes: 2

Views: 283

Answers (2)

Rob
Rob

Reputation: 437381

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

Upvotes: 4

DonMag
DonMag

Reputation: 77423

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

Upvotes: 1

Related Questions