void (^first_animation)();
void (^second_animation)(BOOL finished);
// First animation
first_animation = ^()
{
g_pin_info_screen.view.alpha = 1.0;
};
// Sec
__block NSMutableArray* animationBlocks = [NSMutableArray new];
typedef void(^animationBlock)(BOOL);
// getNextAnimation
// removes the first block in the queue and returns it
animationBlock (^getNextAnimation)() = ^{
if ([animationBlocks count] > 0){
animationBlock block = (animationBlock)[animationBlocks objectAtIndex:0];
[animationBlocks removeObjectAtIndex:0];
return block;
} else {
return ^(BOOL finished){
animationBlocks = nil;
};
}
};
[animationBlocks addObject:^(BOOL finished){
[UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
//my first set of animations
} completion: getNextAnimation()];
}];
[animationBlocks addObject:^(BOOL finished){
[UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
//second set of animations
} completion: getNextAnimation()];
}];
[animationBlocks addObject:^(BOOL finished){
[UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
//third set
} completion: getNextAnimation()];
}];
[animationBlocks addObject:^(BOOL finished){
[UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
//last set of animations
} completion:getNextAnimation()];
}];
// execute the first block in the queue
getNextAnimation()(YES);
With the help of the third party library there is a solution that looks like as below:
First, for convenience, define a category for UIView
like so:
+(RXPromise*) rx_animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations
{
RXPromise* promise = [RXPromise new];
[UIView animateWithDuration:duration animations:animations: ^(BOOL finished){
// ignore param finished here
[promise fulfillWithValue:@"finished"]; // return just a string indicating success
}];
return promise;
}
Then, define any number of asynchronous animations which execute one after the other, as follows:
[UIView rx_animateWithDuration:duration animation:^{
... //define first animation
}]
.then(^id(id result){
// ignore result, it contains the fulfill value of the promise, which is @"finished"
return [UIView rx_animateWithDuration:duration animation:^{
... // define second animation
}];
}, nil)
.then(^id(id result){
return [UIView rx_animateWithDuration:duration animation:^{
... // define third animation
}];
}, nil)
.then(^id(id result){
return [UIView rx_animateWithDuration:duration animation:^{
... // and so force
};
}, nil);
The above statement is asynchronous!
With one line additional code you can achieve cancellation:
RXPromise* rootPromise = [UIView rx_animateWithDuration:duration animation:^{
... //define first animation
}];
rootPromise.then(^id(id result){
return [UIView rx_animateWithDuration:duration animation:^{
... // define second animation
}];
}, nil)
.then(^id(id result){
return [UIView rx_animateWithDuration:duration animation:^{
... // define third animation
}];
}, nil)
...
// later, in case you need to cancel pending animations:
[rootPromise cancel];
"RXPromise" library is available on GitHub: RXPromise. It's specifically designed for these use cases, and more. Due to full disclosure: I'm the author ;)
In the completion handler of the first animation, start the second one.
You need to chain them together by using + (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
Within the options:
argument, you need to include UIViewAnimationOptionBeginFromCurrentState
Good luck!
Just check here: https://gist.github.com/vadimsmirnovnsk/bce345ab81a1cea25a38
You can chain it in functional style:
dispatch_block_t animationsBlock = ^{
[self.view updateConstraintsIfNeeded];
[self.view layoutIfNeeded];
};
[[[[[[[[[BARAnimation construct]
initially:animationsBlock]
animationWithDuration:0.425 animationConditions:^{
[gridView mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(imageView).with.offset(32.0);
}];
} animations:animationsBlock]
animationWithDuration:0.425 animationConditions:^{
[gridView mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(imageView).with.offset(0.0);
}];
} animations:animationsBlock]
animationWithDuration:0.425 animationConditions:^{
[gridView mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(imageView).with.offset(-32.0);
}];
} animations:animationsBlock]
animationWithDuration:0.425 animationConditions:^{
[gridView mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(imageView).with.offset(0.0);
}];
} animations:animationsBlock]
animationWithDuration:0.8 animationConditions:nil animations:^{
foreView.alpha = 1.0;
}]
finally:^{
[self.didEndSubject sendNext:[RACUnit defaultUnit]];
[self.didEndSubject sendCompleted];
}]
run];