The proper way of doing chain animations

前端 未结 5 1783
余生分开走
余生分开走 2020-12-10 09:14
void (^first_animation)();
void (^second_animation)(BOOL finished);


// First animation

first_animation = ^()
{
    g_pin_info_screen.view.alpha = 1.0;
};


// Sec         


        
相关标签:
5条回答
  • 2020-12-10 09:43
    __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);   
    
    0 讨论(0)
  • 2020-12-10 09:55

    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 ;)

    0 讨论(0)
  • 2020-12-10 10:00

    In the completion handler of the first animation, start the second one.

    0 讨论(0)
  • 2020-12-10 10:02

    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!

    0 讨论(0)
  • 2020-12-10 10:05

    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];
    
    0 讨论(0)
提交回复
热议问题