简体   繁体   English

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

[英]How to both scroll and stop UIScrollView programmatically?

There are a lot of similar questions but they all differ from this one. 有很多类似的问题,但是它们都与此问题有所不同。

I have UIScrollView which I could both scroll and stop programmatically. 我有UIScrollView ,可以同时以编程方式滚动和停止。

I scroll via the following code: 我滚动以下代码:

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

And I don't know how to stop it at all. 而且我根本不知道如何阻止它。 In all the cases it won't stop or will stop but it also jumps to newPageRect (for example in the case of removeAllAnimations ). 在所有情况下,它都不会停止或将停止,但也会跳转到newPageRect (例如,对于removeAllAnimations )。

Could you suggest how to stop it correctly? 您能否建议如何正确停止它? Should I possibly change my code for scrolling to another one? 我是否应该更改代码以滚动到另一个代码?

I think this is something you best do yourself. 我认为这是您最好自己做的事情。 It may take you a few hours to create a proper library to animate data but in the end it can be very rewarding. 创建适当的库以对数据进行动画处理可能需要花费几个小时,但最终它可能会非常有意义。

A few components are needed: 需要一些组件:

A time bound animation should include either a CADispalyLink or a NSTimer . 有时间限制的动画应包括CADispalyLinkNSTimer Create a public method such as animateWithDuration: which will start the timer, record a current date and set the target date. 创建一个公共方法,例如animateWithDuration:它将启动计时器,记录当前日期并设置目标日期。 Insert a floating value as a property which should then be interpolated from 0 to 1 through date. 插入一个浮动值作为属性,然后应在0到1的整个日期之间进行插值。 Will most likely look something like that: 很有可能看起来像这样:

- (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
    }
}

As you can see from the comments you should have 2 more calls in this method which will notify the owner/listener to the changes of the animation. 从注释中可以看到,此方法中应该再有2个调用,这将通知所有者/侦听器动画的更改。 This may be achieved via delegates, blocks, invocations, target-selector pairs... 这可以通过委托,块,调用,目标选择器对来实现。

So at this point you have a floating value interpolating between 0 and 1 which can now be used to interpolate the rect you want to be visible. 因此,在这一点上,您可以在0到1之间插入一个浮动值,现在可以使用该值对想要显示的矩形进行插值。 This is quite an easy method: 这是一个很简单的方法:

- (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);
}

So now to put it all together it would look something like so: 因此,现在将它们放在一起看起来像这样:

- (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];
    }];
}

This can be a great system that can be used in very many systems when you want to animate something not animatable or simply have a better control over the animation. 这是一个很棒的系统,当您想要为不可动画的事物设置动画或只是更好地控制动画时,可以在很多系统中使用。 You may add the stop method which needs to invalidate the timer or display link and notify the owner. 您可以添加stop方法,该方法需要使计时器或显示链接无效并通知所有者。

What you need to look out for is not to create a retain cycle. 您需要注意的是不要创建保留周期。 If a class retains the animator object and the animator object retains the listener (the class) you will create a retain cycle. 如果一个类保留了动画设计器对象,而动画设计器对象保留了侦听器(该类),则将创建一个保留循环。

Also just as a bonus you may very easily implement other properties of the animation such as delay by computing a larger start time. 同样,作为奖励,您可以非常轻松地实现动画的其他属性,例如通过计算较大的开始时间来延迟。 You can create any type of curve such as ease-in, ease-out by using an appropriate function for computing the currentValue for instance self.currentValue = pow(interpolation, 1.4) will be much like ease-in. 您可以通过使用适当的函数来计算currentValue (例如self.currentValue = pow(interpolation, 1.4)来创建任何类型的曲线,例如缓入,缓出self.currentValue = pow(interpolation, 1.4)与缓入非常相似。 A power of 1.0/1.4 would be a same version of ease-out. 1.0/1.4将是缓解的相同版本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM