做链动画的正确方法

时间:2013-07-30 14:14:59

标签: ios objective-c ipad

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

}

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

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

5 个答案:

答案 0 :(得分:12)

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

答案 1 :(得分: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];

“RXPromise”库可在GitHub上找到:RXPromise。它专为这些用例而设计,等等。由于完全披露:我是作者;)

答案 2 :(得分: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];

答案 3 :(得分:0)

您需要使用+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion

将它们链接在一起

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

祝你好运!

答案 4 :(得分:0)

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