7

按照 Apple 的建议,我通过将后续调用-animationWithDuration:animation:置于对completion:的另一个调用块中来链接 UIView 动画aanimateWithDuration:animation:completion:,如下所示:

[UIView animateWithDuration:scaleDuration delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
    // Scale the controllers' views down.
    self.view.transform = CGAffineTransformScale(self.view.transform, 0.8, 0.8);
} completion:^(BOOL finished) {
    // Transition to the new view and push on the new view controller.
    [UIView transitionWithView:self.view duration:1 options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionTransitionFlipFromLeft animations:^{
        [self pushViewController:viewController animated:NO];
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:scaleDuration delay:0 options:UIViewAnimationOptionCurveLinear animations:
^{
            // Scale back to the original size.
            self.view.transform = CGAffineTransformScale(self.view.transform, 1.25, 1.25);
        } completion:nil];
    }];
}];

动画都执行正确的顺序,但它们之间有一个微小的延迟,尤其是在-transitionWithView:duration:options:animations:completion:调用之前。如何平滑动画步骤之间的过渡?

4

3 回答 3

2

旁白:您以这种方式滥用导航控制器
有什么特别的原因吗?你不能把presentViewController:animated:completion:它的过渡风格设置为UIModalTransitionStyleFlipHorizontal吗?

回到你的问题:

我很确定口吃来自一个简单的事实,即pushViewController:animated:隐式必须加载要推送的视图控制器的视图,这需要一些时间。

所以如果你不能使用presentViewController:animated:completion:(or presentModalViewController:animated: if you have to support iOS 4) 方法,我鼓励你试试这个:

// ensure the view is already loaded when you invoke `pushViewController:animated:`
[viewController view];

// there is no strict need to calculate those in situ, so we do it up front
CGAffineTransform originalTransform = self.view.transform;
CGAffineTransform downscalingTransform = CGAffineTransformScale(originalTransform, 0.8, 0.8);

// I found it hard to read the block-in-a-block-in-a... while editing here, so I've taken them apart:
void (^scaleDownAnimation)() = ^{
    self.view.transform = downscalingTransform;
};

void (^restoreScaleAnimation)() = ^{
    self.view.transform = originalTransform;
};

void (^pushControllerAnimation)() = ^{
    [self pushViewController:viewController animated:NO];
};

void (^pushAnimationCompletion)(BOOL) = ^(BOOL unused) {
    [UIView animateWithDuration:scaleDuration
                          delay:0
                        options:UIViewAnimationOptionCurveLinear
                     animations:restoreScaleAnimation
                     completion:nil];
};

void (^downscaleCompletion)(BOOL) = ^(BOOL unused){
    UIViewAnimationOptions linearFlipFromLeft = UIViewAnimationOptionCurveLinear | UIViewAnimationOptionTransitionFlipFromLeft;
    [UIView transitionWithView:self.view
                      duration:1
                       options:linearFlipFromLeft
                    animations:pushControllerAnimation
                    completion:pushAnimationCompletion];
};

[UIView animateWithDuration:scaleDuration
                      delay:0
                    options:UIViewAnimationOptionCurveEaseIn
                 animations:scaleDown
                 completion:downscaleCompletion];

请注意,牛肉在前六行之内,其余的只是为了完整性。

于 2012-05-19T08:47:33.217 回答
0

正如你所描述的,我已经毫不拖延地链接了动画。

您正在使用 transitionWithView:duration:options:animations:completion: 动画块是对 pushViewController:animated: 的调用。这对我来说没有任何意义。

transitionWithView:duration:options:animations:completion 从一个子视图过渡到下一个子视图。

pushViewController:animated 是一种导航控制器方法,可将视图控制器推送到导航控制器堆栈上。将这两个一起使用对我来说毫无意义。

如果您希望缩放动画以推送结束,则只需直接从完成块中调用推送动画。

于 2012-05-16T22:06:46.910 回答
0

以我的经验,“使用完成块链接动画”是有缺陷的(在子动画之间产生小的停顿)。我确保没有 loadView/viewDidLoad/viewWillAppear/viewWillLayoutSubviews 滥用发生。

完全相同的代码与“completion-block_chainig”结结巴巴,但如果我将它重新设计为使用关键帧,它就可以正常工作。

所以,而不是(例如)...

        UIView.animate(withDuration: 1, animations: {[weak self] in
            ...
            self?.view.layoutIfNeeded()
        }, completion: { [weak self] _ in
            UIView.animate(withDuration: 1, animations: {
                ...
                self?.view.layoutIfNeeded()
            }, completion: { [weak self] _ in
                UIView.animate(withDuration: 1, animations: {
                    ...
                    self?.view.layoutIfNeeded()
                }, completion: { [weak self] _ in
                    ...
                })
            })
        })

...我反而更喜欢...

        UIView.animateKeyframes(withDuration: 3, delay: 0, options: .calculationModeLinear, animations: {[weak self] in

            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.33, animations: {[weak self] in
                ...
                self?.view.layoutIfNeeded()
            })

            UIView.addKeyframe(withRelativeStartTime: 0.33, relativeDuration: 0.33, animations: {[weak self] in
                ...
                self?.view.layoutIfNeeded()
            })

            UIView.addKeyframe(withRelativeStartTime: 0.66, relativeDuration: 0.33, animations: {[weak self] in
                ...
                self?.view.layoutIfNeeded()
            })

        }, completion: { [weak self] _ in
            ...
        })
于 2017-05-17T15:30:59.647 回答