UIView 动画完成块在其他动画开始时触发

Posted

技术标签:

【中文标题】UIView 动画完成块在其他动画开始时触发【英文标题】:UIView animations completion block firing when an other animation begins 【发布时间】:2010-10-28 18:22:53 【问题描述】:

我在 ios 上使用块基础 API 制作动画。

一个动画有一个完成块,该块在动画结束时被调用,很好。

但是,当用户滚动时,可以多次触发该动画(该动画位于 UITableViewCell 上)。当这种情况发生时,完成块被多次调用。块的finished 参数始终为YES

由于动画实际上并未完成(发生了另一个动画),我认为finished 参数将是 NO,但事实并非如此。

我错过了什么吗?如何避免完成块被多次调用?

【问题讨论】:

您现在是在模拟器中执行此操作,还是尝试在实际设备上运行此操作?滚动时在 UITableViewCells 上运行动画似乎不太合适。滚动时的帧速率是多少? 【参考方案1】:

多次调用完成块只是因为在您的情况下,您的动画被多次触发。发生的事情是,iOS 每次被告知时都会调用您的动画块,可能是在一个单独的线程中。然后,对于每个动画,它都会跟踪其完成情况,并在完成后调用相关的完成块。所以基本上,你会看到你的完成块被触发了多次,每次调用你的动画都会触发一次。请注意,与完成块关联的布尔值特定于该完成块,它不以任何方式引用不同的动画。

回顾一下,您所经历的只是并发的影响。如果这不是您的预期行为,那么您需要相应地修改您的代码。如果您希望您的动画一次触发一个,您可以使用 NSLock(使用关联条件变量进行高级控制的 NSConditionLock),或者,如果您愿意,可以直接使用互斥锁和 Posix pthreads 库来创建要执行的关键部分以一种相互排斥的方式。

【讨论】:

如果没有必要,我宁愿不使用 NSLock。但如果这是唯一的解决方案,我会这样做。然而,一件事没有得到,布尔值什么时候会是 NO?因为与此完成块关联的动画实际上并未完成。 我知道 NSLock 会损害性能,但是我没有看到任何其他解决方案来序列化并发调用。与动画块的完成处理程序关联的布尔值永远不应为 NO,否则,我看不出将其称为“完成”块的意义。无论如何,即使 iOS 在相关动画实际终止之前调用了完成块,您也可以简单地检查块中的布尔值并仅在为 YES 时做出反应。【参考方案2】:

不确定您何时触发动画以及它们是否循环(如 UIActivityView 微调器或其他东西) - 听起来像是表格视图正在滚动的每个像素?

无论如何,也许您可​​以使用 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)。但是您的解决方案将不起作用,因为当“真实”动画仍在进行时会调用“错误”完成块。【参考方案3】:

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

finished 参数现在不相关。我与 Apple 沟通过,他们告诉我它已在 iOS 4.2 中修复。

【讨论】:

我正在使用 ios5,但问题似乎仍未解决。当您说“我通过查看完成块在该块的开头是否相关来解决此问题”时,您能解释一下您的意思吗? 我同意finished 参数似乎无法正常工作。我通过添加 animationCount ivar 获得了所需的行为,我在动画开始和完成时递增/递减。如果它是0,我只运行我的完成块代码。

以上是关于UIView 动画完成块在其他动画开始时触发的主要内容,如果未能解决你的问题,请参考以下文章

使用 Swift 在单个 UIView 上同时进行多个动画

UIView 动画被调用两次,取消动画

如何在代码中调用 UIView 动画

在Vue中使用GSAP完成动画(四)播放组件

在Vue中使用GSAP完成动画(三)动画事件

快速放置在函数中时无法触发uiview.animate