Cocoa touch 为什么在animateWithDuration动画和完成块之间暂停?

Cocoa touch 为什么在animateWithDuration动画和完成块之间暂停?,cocoa-touch,uiview,uinavigationcontroller,core-animation,uiviewanimationtransition,Cocoa Touch,Uiview,Uinavigationcontroller,Core Animation,Uiviewanimationtransition,按照苹果的建议,我将通过在另一个调用aanimateWithDuration:animation:completion:的completion:块中调用-animatewithduration:animation:completion:链接UIView动画,如下所示: [UIView animateWithDuration:scaleDuration delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ // Sca

按照苹果的建议,我将通过在另一个调用
aanimateWithDuration:animation:completion:
completion:
块中调用
-animatewithduration:animation:completion:
链接UIView动画,如下所示:

[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:
调用之前。如何平滑动画步骤之间的过渡?

我毫不延迟地链接了您描述的动画

您正在使用transitionWithView:duration:options:animations:completion:和调用pushViewController:animated:的动画块。那对我来说毫无意义

transitionWithView:持续时间:选项:动画:完成从一个子视图到下一个子视图的过渡

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

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

旁白:
您以这种方式滥用导航控制器有什么特殊原因吗?您不能只使用
presentViewController:animated:completion:
将其转换样式设置为
UIModAltransationStyleFlipHorizontal

回到你的问题:


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

因此,如果您无法使用
presentViewController:animated:completion:
(或presentModalViewController:animated:if you's 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];
注意牛肉在前六行之内,其余的都是为了完整。

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

与“completion-block_chainig”完全相同的代码会出现口吃,但如果我将其返工以使用关键帧,则效果很好

因此,而不是(例如)

。。。我宁愿

        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
            ...
        })

在这种情况下,
self
是否是一个导航控制器,作为您向其发送的
pushViewController:
?什么是预期的动画,在视图之间“翻转”,而不是像普通导航控制器那样左/右滑动?好的。被推送的视图控制器是否实现了
loadView
viewDidLoad
viewWillLayoutSubviews
viewWillLayoutSubviews
?如果是这样的话,请检查他们是否在动画期间接到电话,并确保他们不会做任何需要时间的事情。很抱歉延迟回复,@MattiasWadman,我上周整个星期都在开会。是的,它将在
视图中加载一个AQGridView将出现
,然后加载一个NSFetchedResultsController和一组从磁盘加载图像的视图。这显然会招致一些开销。我想知道我是否能在动画开始前让它这样做…好的。是的,这些图片听起来是一个很好的起点。首先,如果您看到了它们之间的差异,请尝试跳过加载检查。也许你可以通过某种方式预加载图像?一个有点难看的解决方案是让视图控制器在其
init
中加载它,然后在使用它创建视图时将其作为参数传递。谢谢您的检查,@MattiasWadman。如果我减少在
gridView:cellForItemAtIndex:
中所做的工作,肯定会减少时间,特别是如果我删除图像加载。仍有轻微停顿,但已大大减少。我只需要弄清楚如何在动画开始前加载这些东西。我不希望它以推结束。我希望它翻转视图,而不是推动视图。因此,
transitionWithView:duration:options:animations:completion:
调用执行翻转,而
pushViewController:animated:
执行切换视图的实际工作。我设置了
animated:NO
,这样它就不会设置动画。除了非常轻微的停顿外,它看起来相当不错。但是
pushViewController:animated:
不应用于切换视图。仅查看控制器。您可以在控制器内使用动画切换视图。这是另一件事。
pushViewController:animated
是将视图控制器推到UINavigationController上的唯一方法。这就是我正在做的。很抱歉,当我指的是“视图控制器”时,我说了“视图”。谢谢@danyowdee。是在执行动画之前加载视图的主要点,以便在动画期间消除该开销?或者,您是否也认为尝试从动画块中删除所有计算(例如,
downscalingTransform
)很重要?我刚刚加载了视图,没有看到太大的差异。将继续戳它…我在
视图中注释掉了代码willdisease:animated
,暂停时间大大减少,但没有消除。所以很明显,这是由于过渡期间发生的事情。我只需要想一想如何在动画开始前实现这一切。如果我在按下之前调用
view将显示:
,或者将AQGridView的加载移动到
viewDidLoad
,我仍然会得到暂停。但是如果我根本不加载AQGridView,只会有一个非常轻微的停顿。我想知道加载AQGridView会推迟什么?哦,为了回答你的问题,我的设计师合作伙伴设计了一个非常好的过渡动画,将工具栏移出屏幕,将可视视图缩小到80%,然后doi
        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
            ...
        })