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 动画完成块在其他动画开始时触发的主要内容,如果未能解决你的问题,请参考以下文章