Detecting UIScrollView page change

前端 未结 10 2121
鱼传尺愫
鱼传尺愫 2020-12-07 17:11

Is there a way to detect or get a notification when user changes the page in a paging-enabled UIScrollView?

相关标签:
10条回答
  • 2020-12-07 17:47

    First result on google for page detection so I had to answer this with a better solution in my opinion. (even if this question was asked 2 and a half years ago.)

    I'd prefer not to call scrollViewDidScroll just to track the page number. Thats an overkill for something simple as that. Using scrollViewDidEndDecelerating does work and stops on a page change BUT (and it's a big but) if the user will swipe on the screen twice a bit faster than normal scrollViewDidEndDecelerating will be called only once. You can easily go from page #1 to page #3 without processing page #2.

    This solved it completely for me:

    - (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
    {
        scrollView.userInteractionEnabled = NO;
    }
    
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
    {
        //Run your code on the current page
        scrollView.userInteractionEnabled = YES;
    }
    

    That way the user can only swipe one page at a time without the risk described above.

    0 讨论(0)
  • 2020-12-07 17:51

    In paging enabled scroll view you can use scrollViewDidEndDecelerating to know when the view is settled on a page (might be the same page).

    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
    

    scrollViewDidScroll gets called on every movement. And in context of paging enabled view can be used to find when it is scrolled enough to move to next page (if dragging is stopped at that point).

    0 讨论(0)
  • 2020-12-07 17:53

    Swift 4

    I found the best way to do this is by using scrollViewWillEndDragging(_:withVelocity:targetContentOffset:). It lets you predict if paging will occur as soon as you lift your finger off the screen. This example is for paging horizontally.

    Remember to the assign the scrollView.delegate to the object that adopts UIScrollViewDelegate and implements this method.

    var previousPageXOffset: CGFloat = 0.0
    
    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    
        let targetOffset = targetContentOffset.pointee
    
        if targetOffset.x == previousPageXOffset {
            // page will not change
        } else if targetOffset.x < previousPageXOffset {
            // scroll view will page left
        } else if targetOffset.x > previousPageXOffset {
            // scroll view will page right
        }
    
        previousPageXOffset = targetOffset.x
        // If you want to track the index of the page you are on just just divide the previousPageXOffset by the scrollView width.
        // let index = Int(previousPageXOffset / scrollView.frame.width)
    
    
    }
    
    0 讨论(0)
  • 2020-12-07 17:53

    For Swift

    static var previousPage: Int = 0
    func scrollViewDidScroll(_ scrollView: UIScrollView){
        let pageWidth: CGFloat = scrollView.frame.width
        let fractionalPage: CGFloat = scrollView.contentOffset.x / pageWidth
        let page = lround(Double(fractionalPage))
        if page != previousPage{
            print(page)
            // page changed
        }
    }
    
    0 讨论(0)
  • 2020-12-07 17:55

    Use this to detect which page is currently being shown and perform some action on page change:

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
        static NSInteger previousPage = 0;
        CGFloat pageWidth = scrollView.frame.size.width;
        float fractionalPage = scrollView.contentOffset.x / pageWidth;
        NSInteger page = lround(fractionalPage);
        if (previousPage != page) {
            // Page has changed, do your thing!
            // ...
            // Finally, update previous page
            previousPage = page;
        }
    }
    

    If it's acceptable for you to only react to the page change once the scrolling has completely stopped, then it would be best to do the above inside the scrollViewDidEndDecelerating: delegate method instead of the scrollViewDidScroll: method.

    0 讨论(0)
  • 2020-12-07 17:59
    var scrollViewPage = 0
    override func viewDidLoad() {
        super.viewDidLoad()
        scrollViewPage = scrollView.currentPage
    }
    
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        if scrollViewPage != scrollView.currentPage {
            scrollViewPage = scrollView.currentPage
            // Do something with your page update
            print("scrollViewDidEndDecelerating: \(scrollViewPage)")
        }
    }
    

    And Use extension

    extension UIScrollView {
        var currentPage: Int {
            return Int((self.contentOffset.x + (0.5 * self.frame.size.width)) / 
            self.frame.width) + 1
        }
    }
    
    0 讨论(0)
提交回复
热议问题