尽管被取消,UIView animateWithDuration完成已完成= YES?

Bli*_*ixt 9 animation objective-c uiview ios

我正在用户交互上运行此动画,有时动画可能会在正在进行的动画完成之前再次运行.我希望它做的是取消上一个动画并继续新的动画.

[UIView animateWithDuration:duration
                      delay:0
                    options:UIViewAnimationOptionBeginFromCurrentState
                 animations:^{
                     self.bounds = bounds;
                 }
                 completion:^(BOOL finished) {
                     if (finished) {
                         // Do some cleanup after animating.
                     }
                 }];
Run Code Online (Sandbox Code Playgroud)

在视觉上,这似乎有效,但在我的完成块中,我被告知它在两种情况下都已完成,这导致清理代码过早运行.所以第一个动画的完成块在第二个动画完成后立即运行,结果为= YES.我希望它有一个完成的值NO和第二个(一旦完成)YES.

有没有办法知道动画是否完成或是否被另一个取消?

旁注:我尝试使用相同的动画,CABasicAnimation然后我完成= NO第一次和YES第二次,所以我得到的行为似乎是特定的animateWithDuration.

这是一个GIF,显示上面的代码,持续时间为10,完成块更新标签.正如你所看到的,finishedYES每一个动画重启与时间animateWithDuration的呼叫:

Bli*_*ixt 12

因此我进一步调查了这一点,我认为这是iOS 8特定的事情,因为动画现在默认是如何添加的,这意味着动画将继续并相互加起来而不是被取消.

在我的搜索中,我找到了一个名为"构建可中断和响应性交互"的WWDC会话,讨论了这个问题.在会话中,他们声称动画将同时完成,但在我的测试中并非如此(请参阅问题中的GIF).会话中建议的解决方法是使计数器保持动画开始与完成的次数,并在计数器达到零时执行动画后动作.这有点hacky,但有效.这是为此调整的问题代码:

// Add this property to your class.
self.runningAnimations++;
[UIView animateWithDuration:duration
                      delay:0
                    options:UIViewAnimationOptionBeginFromCurrentState
                 animations:^{
                     self.bounds = bounds;
                 }
                 completion:^(BOOL finished) {
                     if (--self.runningAnimations == 0) {
                         // Do some cleanup after animating.
                     }
                 }];
Run Code Online (Sandbox Code Playgroud)

显然你需要一个单独的计数器用于每种类型的动画,所以它最终会变得有点混乱,但我不认为除非你CAAnimation直接开始使用,否则有更好的方法.