ios 如何检测 UIScrollView 何时完成滚动

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/993280/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 16:01:41  来源:igfitidea点击:

How to detect when a UIScrollView has finished scrolling

iosiphoneuiscrollview

提问by Michael Gaylord

UIScrollViewDelegate has got two delegate methods scrollViewDidScroll:and scrollViewDidEndScrollingAnimation:but neither of these tell you when scrolling has completed. scrollViewDidScrollonly notifies you that the scroll view did scroll not that it has finished scrolling.

UIScrollViewDelegate 有两个委托方法scrollViewDidScroll:scrollViewDidEndScrollingAnimation:但它们都不会告诉您滚动何时完成。scrollViewDidScroll只通知您滚动视图确实滚动而不是它已完成滚动。

The other method scrollViewDidEndScrollingAnimationonly seems to fire if you programmatically move the scroll view not if the user scrolls.

另一种方法scrollViewDidEndScrollingAnimation似乎仅在您以编程方式移动滚动视图时才触发,而不是在用户滚动时触发。

Does anyone know of scheme to detect when a scroll view has completed scrolling?

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

回答by Ashley Smart

The 320 implementationsare so much better - here is a patch to get consistent start/ends of the scroll.

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

回答by Suvesh Pratapa

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

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

- (void)stoppedScrolling {
    // ...
}

回答by texmex5

I think scrollViewDidEndDecelerating is the one you want. Its UIScrollViewDelegates optional method:

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

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

Tells the delegate that the scroll view has ended decelerating the scrolling movement.

告诉委托滚动视图已结束减速滚动移动。

UIScrollViewDelegate documentation

UIScrollViewDelegate 文档

回答by Aurelien Porte

For all scrolls related to dragging interactions, this will be sufficient:

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

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

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

Now, if your scroll is due to a programmatic setContentOffset/scrollRectVisible (with animated= YES or you obviously know when scroll is ended):

现在,如果您的滚动是由于程序化的 setContentOffset/scrollRectVisible(使用animated= YES 或者您显然知道滚动何时结束):

 - (void)scrollViewDidEndScrollingAnimation {
     _isScrolling = NO;
}

If your scroll is due to something else (like keyboard opening or keyboard closing), it seems like you'll have to detect the event with a hack because scrollViewDidEndScrollingAnimationis not useful either.

如果您的滚动是由于其他原因(例如键盘打开或键盘关闭),则似乎您必须使用 hack 来检测该事件,因为这scrollViewDidEndScrollingAnimation也没有用。

The case of a PAGINATEDscroll view:

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

Because, I guess, Apple apply an acceleration curve, scrollViewDidEndDeceleratingget called for every drag so there's no need to use scrollViewDidEndDraggingin this case.

因为,我想,Apple 应用了一条加速曲线,scrollViewDidEndDecelerating每次拖动都会被调用,所以scrollViewDidEndDragging在这种情况下不需要使用。

回答by Wayne

This has been described in some of the other answers, but here's (in code) how to combine scrollViewDidEndDeceleratingand scrollViewDidEndDragging:willDecelerateto perform some operation when scrolling has finished:

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

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

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

- (void)stoppedScrolling
{
    // done, do whatever
}

回答by Aberrant

I only just found this question, which is pretty much the same I asked: How to know exactly when a UIScrollView's scrolling has stopped?

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

Though didEndDecelerating works when scrolling, panning with stationary release does not register.

尽管 didEndDecelerating 在滚动时有效,但使用固定释放进行平移不会注册。

I eventually found a solution. didEndDragging has a parameter WillDecelerate, which is false in the stationary release situation.

我最终找到了解决方案。didEndDragging 有一个参数 WillDecelerate,在静止释放情况下为 false。

By checking for !decelerate in DidEndDragging, combined with didEndDecelerating, you get both situations that are the end of scrolling.

通过检查 DidEndDragging 中的 !decelerate 并结合 didEndDecelerating,您可以获得滚动结束的两种情况。

回答by Umair

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

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

func scrollingFinished(scrollView: UIScrollView) {
   // Your code
}

回答by Zappel

If you're into Rx, you can extend UIScrollView like this:

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

import RxSwift
import RxCocoa

extension Reactive where Base: UIScrollView {
    public var didEndScrolling: ControlEvent<Void> {
        let source = Observable
            .merge([base.rx.didEndDragging.map { !
scrollView.rx.didEndScrolling.subscribe(onNext: {
    // Do what needs to be done here
})
}, base.rx.didEndDecelerating.mapTo(true)]) .filter {
func scrollViewDidScroll(scrollView: UIScrollView) {
     // example code
}
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        // example code
}
func scrollViewDidEndZooming(scrollView: UIScrollView, withView view: UIView!, atScale scale: CGFloat) {
      // example code
}
} .mapTo(()) return ControlEvent(events: source) } }

which will allow you to just do like this:

这将允许您这样做:

-(void)scrollViewDidScroll:(UIScrollView *)sender 
{   
    if(self.scrollView_Result.contentOffset.x == self.scrollView_Result.frame.size.width)       {
    // You have reached page 1
    }
}

This will take into account both dragging and deceleration.

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

回答by zzzz

Swift version of accepted answer:

已接受答案的 Swift 版本:

##代码##

回答by Ege Akpinar

I've tried Ashley Smart's answer and it worked like a charm. Here's another idea, with using only scrollViewDidScroll

我已经尝试过 Ashley Smart 的答案,它的效果非常好。这是另一个想法,只使用 scrollViewDidScroll

##代码##

I just had two pages so it worked for me. However, if you have more than one page, it could be problematic (you could check whether the current offset is a multiple of the width but then you wouldn't know if the user stopped at 2nd page or is on his way to 3rd or more)

我只有两页,所以它对我有用。但是,如果您有多个页面,则可能会出现问题(您可以检查当前偏移量是否是宽度的倍数,但您将不知道用户是停在第 2 页还是正在前往第 3 页或更多的)