2

我有一个 UIScrollView 的子类,用于图像幻灯片,具有无限滚动和圆形幻灯片。

我曾经以这种方式为过渡设置动画:(因为我希望过渡更慢)

[UIView animateWithDuration:1.0 
                      delay:0 options:(UIViewAnimationCurveEaseOut)
                 animations:^{
                         self.scrollView.contentOffset = newOffset;}
                 completion:NULL];

它工作得很好。

然后我观看了 WWDC 2011 的讲座“高级滚动技术”,他们建议通过覆盖来实现无限滚动layoutSubviews

所以我改变了我的实现并覆盖layoutSubviews

一旦我这样做了,过渡动画就停止了工作。

如果我注释掉我的自定义 layoutSubviews - 它又可以工作了!

为什么??

在覆盖 layoutSubviews 时,我可以做些什么来制作自己的滚动动画?

谢谢!

4

1 回答 1

3

好的,我想我找到了问题所在,并找到了可能的解决方法。

理解问题的关键是理解当你打电话时

[UIView animateWithDuration...]

您在动画块内更改的所有属性都会立即更改。它们不会随着动画的实际执行而改变(视觉上)。

所以在我的例子中,我将 contentOffset 设置为我的目标值。此操作立即调用 layoutSubviews。

在我的 layoutSubviews 实现中,我正在检查是否已经积累了足够的移动。如果是这样 - 我正在重新排列我的 ImageView,并将 contentOffset 设置为其初始值。一旦我这样做了,就没有什么可以动画了,因为什么都没有改变!

  1. 动画 contentOffset 到 X:
    • 调用 setContentOffset 到 X:
      • 调用 layoutSubview
        • 将 contentOffset 设置回 Y!(重新排列视图后)
    • 在这一点上没有任何动画...

可能的修复

我不确定这是否是正确的方法,但它的工作正常。所以我们需要做的是确保在动画块中间时不会对 layoutSubviews 进行任何更改。

所以我创建了一个名为 isAnimating 的 BOOL 实例变量,并在动画块中适当地设置它:

self.isAnimating = YES;
[UIView animateWithDuration:self.transitionDuration 
                      delay:0 
                    options:(UIViewAnimationOptionCurveEaseOut) 
                 animations:^{
    self.contentOffset = newOffset;
}

                 completion:^(BOOL finished) {
        self.isAnimating = NO;
        [self setNeedsLayout];
}];

现在在 layoutSubviews 中我们需要考虑 isAnimating:

-(void) layoutSubviews
{
    [super layoutSubviews];
    if (self.isAnimating == NO)
    {
        [self rearrangeIfNecessary];
    }
}

它又开始工作了!

于 2012-03-20T13:20:27.063 回答