如何以编程方式滚动和停止 UIScrollView?

How to both scroll and stop UIScrollView programmatically?

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

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

我通过以下代码滚动:

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

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

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

我认为这是你最好自己做的事情。创建一个适当的库来为数据制作动画可能需要花费您几个小时,但最终您会收获颇丰。

需要几个组件:

时间限制动画应包括 CADispalyLinkNSTimer。创建一个 public 方法,例如 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
    }
}

正如您从评论中看到的那样,您应该在此方法中再调用 2 次,这将通知 owner/listener 动画的变化。这可以通过委托、块、调用、目标选择器对来实现...

所以此时你有一个介于 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方法需要使定时器失效或显示link并通知所有者。

您需要注意的是不要创建保留循环。如果 class 保留动画师对象并且动画师对象保留侦听器(class),您将创建一个保留循环。

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