如何在自定义动画期间以与UIScrollView相同的方式调用scrollViewDidScroll:?

6
我有一个非常大的水平滚动的UIScrollView,它正在重用其子视图(当它们超出可见区域时移动和更新它们,类似于UITableView重用单元格)。这依赖于scrollViewDidScroll:委托调用,它给我实际的contentOffset,然后我决定何时重用特定的子视图。到目前为止都很好。
有时我需要以自定义动画(惯性和反弹回最终位置)编程更改contentOffset。我可以使用核心动画轻松实现这一点。
问题是,在自定义动画期间,scrollViewDidScroll:委托方法不会被调用->我必须手动执行它,以便子视图重用起作用。我尝试使用每0.02秒触发一次的计时器来调用它。现在有两个问题:
1.我必须使用[[_scrollView.layer presentationLayer] bounds] .origin.x获取UIScrollView contentOffset,因为在动画期间正常的_scrollView.contentOffset不会改变。但是,presentationLayer中的信息对于精确同步不足够-有时会有点晚。
2.问题是当新的contentOffset远离当前位置时。它看起来像内置的UIScrollView动画是CAKeyframeAnimation,并且scrollViewDidScroll应该在关键帧位置上调用。但是我无法获得这些。
有人能否阐明UIScrollView在setContentOffset:X animated:YES期间何时以及如何调用scrollViewDidScroll?是否可能在不违反App Store规则的情况下重现它?
1个回答

4

首先,我不会使用延迟为0.02秒的NSTimer - 定时器并不是用于此目的的。尝试使用CADisplayLink,它每帧触发一次。


在回调方法中,如果您的自定义动画正在运行,可以运行您自己的物理代码并相应地调用- setContentOffset:animated:方法。这甚至允许您指数级缓解,而CA则不会。


非常感谢,同步现在好多了。但仍有一个问题:当滚动到长距离时,视图复用未能跟上滚动的速度。当通过触摸事件(用户滚动)很快地滚动时也是如此。一旦停止使用演示层来进行位置跟踪和用户滚动时,即使是最快的轻扫滚动也会变得流畅。因此,似乎向演示层请求数据的方式有些缓慢。是否有办法在滚动期间强制UIScrollView更新contentOffset以实现默认行为?这可能会加快速度。 - Vilém Kurz
抱歉,我应该告诉你:在CADisplayLink的回调中调用-setNeedsLayout或者你执行重用代码的任何方法。 - Christian Schnorr
是的,我在回调中调用了scrollViewDidScroll:。明天我会尝试使用Instruments进行分析,找出性能问题所在。你在setNeedsLayout中执行重用操作吗? - Vilém Kurz
好的。如果你还有问题,能否通过邮件联系我(请查看我的个人资料),这样我们就不必在 Stack Overflow 上继续讨论了? - Christian Schnorr
解决方案是在CADisplayLink回调中调用setContentOffset:X。偏移量X是传入动画函数的时间的结果。每个setContentOffset调用都会与显示帧速率完美同步地调用scrollViewDidScroll:委托方法。这正是UIScrollView在内部工作的方式。非常感谢Jenox指引我正确的方向。 - Vilém Kurz

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