【问题标题】:How to both scroll and stop UIScrollView programmatically?如何以编程方式滚动和停止 UIScrollView?
【发布时间】:2015-08-28 10:51:10
【问题描述】:

有很多类似的问题,但都与这个不同。

我有UIScrollView,我可以通过编程方式滚动和停止。

我通过以下代码滚动:

[UIView animateWithDuration:3
                              delay:0
                            options:UIViewAnimationOptionCurveEaseInOut
                         animations:^{ [self.scrollView scrollRectToVisible:newPageRect animated:NO]; }];

而且我根本不知道如何阻止它。在所有情况下,它都不会停止或将停止但它也会跳转到newPageRect(例如removeAllAnimations)。

您能建议如何正确停止它吗?我是否应该更改我的代码以滚动到另一个代码?

【问题讨论】:

  • 你自己试过了吗?那篇文章没有任何效果,最后一个答案甚至是离题的。
  • 我看不出有任何理由让这个滚动从这段代码中连续发生。也许它正在处理调用它的代码。你也可以上传那个代码。另外,我认为您在animateWithDuration: 方法中缺少completion
  • 在这段代码中,我尝试滚动到scrollView 的末尾(或开头),我希望在某些事件上停止它。因此,我不是执行多个小步骤,而是执行一个大步骤,并计划在某个地方停止它。

标签: ios animation scroll uiscrollview animatewithduration


【解决方案1】:

我认为这是你最好自己做的事情。创建一个合适的库来为数据制作动画可能需要几个小时,但最终它会非常有益。

需要几个组件:

有时间限制的动画应包含CADispalyLinkNSTimer。创建一个公共方法,例如animateWithDuration:,它将启动计时器、记录当前日期并设置目标日期。插入一个浮点值作为属性,然后将其从 0 插入到 1 到日期。很可能看起来像这样:

- (void)onTimer {
    NSDate *currentTime = [NSDate date];
    CGFloat interpolation = [currentTime timeIntervalSinceDate:self.startTime]/[self.targetTime timeIntervalSinceDate:self.startTime];

    if(interpolation < .0f) { // this could happen if delay is implemented and start time may actually be larger then current
        self.currentValue = .0f;
    }
    else if(interpolation > 1.0f) { // The animation has ended
        self.currentValue = 1.0f;
        [self.displayLink invalidate]; // stop the animation
        // TODO: notify owner that the animation has ended
    }
    else {
        self.currentValue = interpolation;
        // TODO: notify owner of change made
    }
}

正如您从 cmets 中看到的那样,您应该在此方法中再调用 2 次,这将通知所有者/侦听器动画的更改。这可以通过委托、块、调用、目标选择器对来实现...

所以此时你有一个在 0 和 1 之间插值的浮点值,现在可以使用它来插值你想要可见的矩形。这是一个相当简单的方法:

- (CGRect)interpolateRect:(CGRect)source to:(CGRect)target withScale:(CGFloat)scale
{
    return CGRectMake(source.origin.x + (target.origin.x-source.origin.x)*scale,
                      source.origin.y + (target.origin.y-source.origin.y)*scale,
                      source.size.width + (target.size.width-source.size.width)*scale,
                      source.size.height + (target.size.height-source.size.height)*scale);
}

所以现在把它们放在一起看起来像这样:

- (void)animateVisibleRectTo:(CGRect)frame {
    CGRect source = self.scrollView.visibleRect;
    CGRect target = frame;
    [self.animator animateWithDuration:.5 block:^(CGFloat scale, BOOL didFinish) {
        CGRect interpolatedFrame = [Interpolator interpolateRect:source to:target withScale:scale];
        [self.scrollView scrollRectToVisible:interpolatedFrame animated:NO];
    }];
}

这是一个很棒的系统,当您想要为不可动画的东西制作动画或只是对动画有更好的控制时,它可以在很多系统中使用。您可以添加stop方法,该方法需要使计时器失效或显示链接并通知所有者。

您需要注意的不是创建保留周期。如果一个类保留了 animator 对象,而 animator 对象保留了侦听器(类),您将创建一个保留循环。

此外,您还可以通过计算更大的开始时间轻松实现动画的其他属性,例如延迟。您可以通过使用适当的函数来计算 currentValue 来创建任何类型的曲线,例如缓入、缓出,例如 self.currentValue = pow(interpolation, 1.4) 将很像缓入。 1.0/1.4 的幂将是相同版本的缓出。

【讨论】:

  • 我会将其标记为答案。突然我发现在我的情况下我需要一个线性动画/速度。因此,按照您的建议,通过NSTimer 解决我的问题很容易
猜你喜欢
  • 2011-03-25
  • 2011-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多