当另一个动画开始时,UIView动画完成块是否会触发?

4
我在iOS中使用块基础API进行动画。其中一个动画具有完成块,在动画结束时调用该块,很好。
然而,当用户滚动时(该动画位于UITableViewCell上),该动画可以被多次触发。这种情况下,完成块将被多次调用。该块的finished参数始终为YES。
由于动画实际上并没有完成(其他动画已经发生),我认为finished参数应该是NO,但事实并非如此。
我错过了什么?如何避免多次调用完成块?

你现在是在模拟器上进行还是已经尝试在实际设备上运行了?在滚动时在UITableViewCells上运行动画似乎不是合适的做法。你在滚动时的帧率是多少? - runmad
3个回答

5
完成块被多次调用,只是因为在你的情况下,动画被多次触发。iOS每次告知时都会调用动画块,可能还在单独的线程中。然后,对于每个动画,它都会跟踪其完成情况,并在完成后调用关联的完成块。因此,基本上,你会看到你的完成块多次触发,每次触发都是针对你的动画调用的。请注意,与完成块关联的布尔值仅特定于该完成块,它不以任何方式引用不同动画。
简而言之,你正在经历并发的影响。如果这不是你想要的行为,那么你需要相应地修改你的代码。如果你希望你的动画一个接一个地触发,你可以使用NSLock(NSConditionLock用于使用相关条件变量进行高级控制)或者如果你愿意,直接使用互斥锁和Posix pthreads库来创建一个互斥执行的关键部分。

如果不必要的话,我宁愿不使用 NSLock。但如果那是唯一的解决方案,我就会这么做。但有一件事我不明白,什么情况下布尔值是 NO?因为与此完成块相关联的动画实际上没有完成。 - gcamp
我知道 NSLock 会影响性能,不过我没找到其他解决并发调用顺序的方法。与动画块相关联的完成处理程序的布尔值永远不应该是 NO,否则就没有必要称其为“完成”块了。即便如此,在 iOS 实际终止相关联的动画之前调用完成块,你也可以简单地检查块中的布尔值,并只有在它为 YES 时才做出反应。 - Massimo Cafaro

2

不确定您何时触发动画以及它们是否循环播放(例如UIActivityView spinner) - 听起来似乎是每个像素都在滚动表格视图?

无论如何,也许您可以使用UIScrollView代理方法,并告诉每个单元格在scrollViewWillBeginDragging:上启动动画,并告诉每个单元格在scrollViewDidEndDragging:上停止。

您可以为UITableViewCell设置一个布尔值isAnimating,如果当前正在进行动画,则什么也不做。

if (isAnimating) {
     // ... do nothing
} else {
     // Start your animation
}

或者继续使用布尔值,但只有在当前未进行动画时才触发动画。然后在您的finished参数中将isAnimating设置为NO

if (isAnimating) {
         // ... do nothing
    } else {
         [UIView animateWithDuration:0.3f
                          animations:^{
                                     // animations...
                                     isAnimating = YES;
                                     }
                          completion:^{
                                     isAnimating = NO;
                                     }
          ];    
}

我的帧率还不错(约为45-50 fps)。但是你的解决方案行不通,因为在“真正”的动画仍在进行时,会调用“错误”的完成块。 - gcamp

0

我通过查看完成块是否在该块的开头相关来解决了这个问题。

finished参数现在并不相关。我已经与苹果公司沟通,他们告诉我这个问题在iOS 4.2中已经修复。


我正在使用ios5,但问题似乎仍未解决。当你说“我通过查看完成块是否在该块的开头相关来解决此问题”时,你能解释一下你的意思吗? - Ser Pounce
我同意finished参数似乎没有正常工作。我通过添加一个animationCount实例变量来获得所需的行为,当动画开始和完成时我会递增/递减它。只有在animationCount为0时才运行我的完成块代码。 - zekel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接