Detecting UIScrollView page change

前端 未结 10 2122
鱼传尺愫
鱼传尺愫 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 18:06

    Cut and paste for 2019

    It's not so easy to do this:

    var quantumPage: Int = -100 {   // the UNIQUELY LANDED ON, NEVER REPEATING page
        didSet {
            print(">>>>>> QUANTUM PAGE IS \(quantumPage)")
            pageHasActuallyChanged() // your function
        }
    }
    
    private var possibleQuantumPage: Int = -100 {
        didSet {
            if oldValue != possibleQuantumPage {
                quantumPage = possibleQuantumPage
            }
        }
    }
    
    public func scrollViewDidEndDragging(
                        _ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if decelerate == false {
            possibleQuantumPage = currentPageEvenIfInBetween
        }
    }
    
    public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        possibleQuantumPage = currentPageEvenIfInBetween
    }
    
    var currentPageEvenIfInBetween: Int {
       return Int((self.contentOffset.x + (0.5 * self.frame.width)) / self.frame.width)
    }
    

    Works perfectly.

    pageHasActuallyChanged will only be called when the user changes pages in what humans would consider "changing pages".

    Be aware: the bringup is tricky:

    This is difficult to initialize at bringup time, and will depend on how you are using the paged system.

    In any paged system you will very likely have something like "scrollToViewAtIndex..."

    open func scrollToViewAtIndexForBringup(_ index: Int) {
        if index > -1 && index < childViews.count {
            
            let w = self.frame.size.width
            let h = self.frame.size.height
            
            let frame = CGRect(x: CGFloat(index)*w, y: 0, width: w, height: h)
            scrollRectToVisible(frame, animated: false) // NOTE THE FALSE
            
            // AND IMPORTANTLY:
            possibleQuantumPage = currentPageEvenIfInBetween
        }
    }
    

    So, if the user opens the "book" at page 17, in your boss class you'd be calling that function to set it to "17" on bringup.

    In such an example, you'd just have to remember that you must set initially our possibleQuantumPage value in any such bringup functions; there's no really generalized way to handle the starting situation.

    After all you may, just for example, want to "quickly scroll" to the bringup page, and, who knows what that "means" in a quantumPage situation. So, be sure to initialize your quantum page system carefully during bringup, based on your situation.

    In any event, just copy and paste the five functions at the top to get perfect quantum paging.

    0 讨论(0)
  • 2020-12-07 18:09

    Implement the delegate of UIScrollView. This method is what you are looking for.

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView
    
    0 讨论(0)
  • 2020-12-07 18:11

    How about combining two methods of UIScrollViewDelegate?

    In scrollViewDidEndDragging(_:willDecelerate:), if it stops right away, we do the page calculation; if it is decelerating, we let it go and it will be caught by scrollViewDidEndDecelerating(_:).

    The code is tested with XCode version 7.1.1, Swift version 2.1

    class ViewController: UIViewController, UIScrollViewDelegate {
    
      // MARK: UIScrollViewDelegate
      func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if decelerate == false {
            let currentPage = scrollView.currentPage
            // Do something with your page update
            print("scrollViewDidEndDragging: \(currentPage)")
        }
      }
    
      func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
        let currentPage = scrollView.currentPage
        // Do something with your page update
        print("scrollViewDidEndDecelerating: \(currentPage)")
      }
    
    }
    
    extension UIScrollView {
       var currentPage: Int {
          return Int((self.contentOffset.x+ (0.5*self.frame.size.width))/self.frame.width)+1
       }
    }
    
    0 讨论(0)
  • 2020-12-07 18:12

    Here is the swift solution for this.

    Make two properties currentPage and previousPage in the class where you are implementing your code and initialize them to 0.

    Now update currentPage from scrollViewDidEndDragging(:willDecelerate:) and scrollViewDidEndDecelerating(:scrollView:).

    And then update previousPage in scrollViewDidEndScrollingAnimation(_:scrollView:)

        //Class Properties
        var currentPage = 0
        var previousPage = 0
    
    func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
            updatePage(scrollView)
            return
        }
    
     func scrollViewDidEndDecelerating(scrollView: UIScrollView){
            updatePage(scrollView)
            return
        }
    
    
     func updatePage(scrollView: UIScrollView) {
            let pageWidth:CGFloat = scrollView.frame.width
            let current:CGFloat = floor((scrollView.contentOffset.x-pageWidth/2)/pageWidth)+1
            currentPage = Int(current)
    
            if currentPage == 0 {
                  // DO SOMETHING
            }
            else if currentPage == 1{
                  // DO SOMETHING
    
            }
        }
    
    func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {
         if previousPage != currentPage {
              previousPage = currentPage
              if currentPage == 0 {
                  //DO SOMETHING
                 }else if currentPage == 1 {
                   // DO SOMETHING
               }
           }
       }
    
    0 讨论(0)
提交回复
热议问题