3
void (^first_animation)();
void (^second_animation)(BOOL finished);


// First animation

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


// Second animation

second_animation = ^(BOOL finished)
{
    g_shadow_layer.opacity = 0.0;

    void (^set_opacity_to_1)();

    set_opacity_to_1 = ^()
    {
        g_shadow_layer.opacity = 1.0;
    };

    [UIView animateWithDuration : 2.0
            delay               : 0.0
            options             : UIViewAnimationCurveEaseInOut
            animations          : set_opacity_to_1
            completion          : nil
     ];

};



// Begin the animations

{

    float duration;

    duration = 0.35;

    [UIView animateWithDuration : duration
            delay               : 0.00
            options             : UIViewAnimationCurveEaseInOut
            animations          : first_animation
            completion          : second_animation
    ];

}

第一个动画按预期执行。但是第二个动画完成但没有任何动画。

希望有人可以评论上述方案是否是这样做的正确方法。

4

5 回答 5

13
__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);   
于 2013-07-30T20:07:13.923 回答
2

在第三方库的帮助下,有一个如下所示的解决方案:

首先,为方便起见,为如下定义一个类别UIView

+(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;
}

然后,定义任意数量的异步动画,它们一个接一个地执行,如下所示:

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

上面的语句是异步的!

使用一行附加代码,您可以实现取消:

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

GitHub 上提供了“RXPromise”库:RXPromise。它专为这些用例等而设计。由于完全披露:我是作者;)

于 2013-08-02T18:54:51.500 回答
1

只需在这里查看: https ://gist.github.com/vadimsmirnovnsk/bce345ab81a1cea25a38

您可以将其链接为功能样式:

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];
于 2016-03-13T13:56:02.823 回答
0

您需要通过使用将它们链接在一起+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion

options:参数中,您需要包括UIViewAnimationOptionBeginFromCurrentState

祝你好运!

于 2013-07-30T15:47:33.377 回答
0

在第一个动画的完成处理程序中,启动第二个动画。

于 2013-07-30T19:58:49.553 回答