如何检测UIScrollView何时完成滚动

Mic*_*ord 140 iphone uiscrollview ios

UIScrollViewDelegate有两个委托方法scrollViewDidScroll:,scrollViewDidEndScrollingAnimation:但这些方法都不能告诉你滚动完成的时间.scrollViewDidScroll只通知您滚动视图确实滚动而不是滚动完成.

scrollViewDidEndScrollingAnimation如果您以编程方式移动滚动视图而不是用户滚动,则另一种方法似乎只会触发.

有没有人知道滚动视图完成滚动时检测的方案?

Ash*_*art 170

320点的实现是好多了-这里是一个补丁来获得滚动一致的开始/结束.

-(void)scrollViewDidScroll:(UIScrollView *)sender 
{   
[NSObject cancelPreviousPerformRequestsWithTarget:self];
    //ensure that the end of scroll is fired.
    [self performSelector:@selector(scrollViewDidEndScrollingAnimation:) withObject:sender afterDelay:0.3]; 

...
}

-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
...
}
Run Code Online (Sandbox Code Playgroud)

  • 应该是[self performSelector:@selector(scrollViewDidEndScrollingAnimation :) withObject:sender afterDelay:0.3] (4认同)
  • 老实说,我无法相信我使用的是iOS 9.3,即2016年2月,这仍然是解决此问题的最佳方法。谢谢,像魅力一样工作 (2认同)

Suv*_*apa 149

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    [self stoppedScrolling];
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    if (!decelerate) {
        [self stoppedScrolling];
    }
}

- (void)stoppedScrolling {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

  • 它看起来只有在减速时才有效.如果你慢慢平移,然后释放,它不会调用didEndDecelerating. (12认同)
  • 虽然它是官方API.它实际上并不总是像我们期望的那样工作.@Ashley Smart提供了更实用的解决方案. (3认同)

tex*_*ex5 21

我认为scrollViewDidEndDecelerating是你想要的.它的UIScrollViewDelegates可选方法:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
Run Code Online (Sandbox Code Playgroud)

告诉代表滚动视图已经结束减速滚动运动.

UIScrollViewDelegate文档


Aur*_*rte 20

对于与拖动交互相关的所有滚动,这就足够了:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    _isScrolling = NO;
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    if (!decelerate) {
        _isScrolling = NO;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果您的滚动是由编程的setContentOffset/scrollRectVisible(使用animated= YES或你很明显知道何时滚动结束):

 - (void)scrollViewDidEndScrollingAnimation {
     _isScrolling = NO;
}
Run Code Online (Sandbox Code Playgroud)

如果您的滚动是由于其他原因(如键盘打开或键盘关闭),您似乎必须通过黑客检测事件,因为scrollViewDidEndScrollingAnimation它也没用.

一个的情况下分页滚动视图:

因为,我猜,Apple会应用加速度曲线,scrollViewDidEndDecelerating每次拖动都会调用,因此scrollViewDidEndDragging在这种情况下无需使用.


Way*_*ett 19

这已在其他一些答案中进行了描述,但这里(在代码中)如何在滚动完成时组合scrollViewDidEndDeceleratingscrollViewDidEndDragging:willDecelerate执行某些操作:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    [self stoppedScrolling];
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView 
                  willDecelerate:(BOOL)decelerate
{
    if (!decelerate) {
        [self stoppedScrolling];
    }
}

- (void)stoppedScrolling
{
    // done, do whatever
}
Run Code Online (Sandbox Code Playgroud)


Abe*_*ant 7

我刚刚发现了这个问题,这跟我问的几乎一样: 如何准确知道UIScrollView的滚动何时停止?

虽然在滚动时didEndDecelerating工作,但是使用固定释放进行平移不会注册.

我终于找到了解决方案.didEndDragging有一个参数WillDecelerate,在静止释放情况下是假的.

通过在DidEndDragging中检查!减速,结合didEndDecelerating,您将获得两种滚动结束的情况.


Xer*_*nox 5

如果有人需要,这是 Swift 中的 Ashley Smart 答案

func scrollViewDidScroll(_ scrollView: UIScrollView) {
        NSObject.cancelPreviousPerformRequests(withTarget: self)
        perform(#selector(UIScrollViewDelegate.scrollViewDidEndScrollingAnimation), with: nil, afterDelay: 0.3)
    ...
}

func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
        NSObject.cancelPreviousPerformRequests(withTarget: self)
    ...
}
Run Code Online (Sandbox Code Playgroud)


小智 5

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    scrollingFinished(scrollView: scrollView)
}

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if decelerate {
        //didEndDecelerating will be called for sure
        return
    }
    scrollingFinished(scrollView: scrollView)        
}

func scrollingFinished(scrollView: UIScrollView) {
   // Your code
}
Run Code Online (Sandbox Code Playgroud)


Zap*_*pel 5

如果你喜欢 Rx,你可以像这样扩展 UIScrollView:

import RxSwift
import RxCocoa

extension Reactive where Base: UIScrollView {
    public var didEndScrolling: ControlEvent<Void> {
        let source = Observable
            .merge([base.rx.didEndDragging.map { !$0 },
                    base.rx.didEndDecelerating.mapTo(true)])
            .filter { $0 }
            .mapTo(())
        return ControlEvent(events: source)
    }
}
Run Code Online (Sandbox Code Playgroud)

这将允许您这样做:

scrollView.rx.didEndScrolling.subscribe(onNext: {
    // Do what needs to be done here
})
Run Code Online (Sandbox Code Playgroud)

这将同时考虑拖动和减速。