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

时间:2015-02-23 05:02:51

标签: ios objective-c animation uiview

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

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

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

有没有办法知道动画是否已完成或是否已被其他人取消?

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

这是一个GIF,显示上面的代码,其持续时间为10,完成块更新标签。如您所见,每次使用finished调用重新启动动画时,YES都为animateWithDuration

2 个答案:

答案 0 :(得分:12)

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

在我的搜索中,我找到a WWDC session called "Building Interruptible and Responsive Interactions"来讨论这个问题。在会话中,他们声称动画将同时完成,但在我的测试中并非如此(请参阅问题中的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.
                     }
                 }];

显然,你需要为每种类型的动画设置一个单独的计数器,这样最终会变得有些混乱,但除非你开始使用{{{},否则我认为没有更好的方法。 1}}直接。

答案 1 :(得分:0)

您尝试取消动画的方法是什么?

theView_ = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[theView_ setBackgroundColor:[UIColor magentaColor]];
[self.view addSubview:theView_];

[UIView animateWithDuration:10
                 animations:^{
                     theView_.frame = CGRectMake(200, 200, 50, 50);
                 } completion:^(BOOL finished) {
                     NSLog(@"done : %@", @(finished));
                     if(finished) {

                     }
                     else {

                     }
                 }];

[self performSelector:@selector(cancelAnimation) withObject:nil afterDelay:2];

cancelAnimation方法如下:

- (void)cancelAnimation {
    NSLog(@"cancel");
    [theView_.layer removeAllAnimations];

}

动画取消后,finished将返回false

日志消息符合预期:

2015-02-23 14:13:58.625 TestPrj[47338:6070317] cancel
2015-02-23 14:13:58.626 TestPrj[47338:6070317] done : 0