Get scroll position of UIPageViewController

后端 未结 6 930
轻奢々
轻奢々 2020-12-14 18:23

I am using a UIPageViewController, and I need to get the scroll position of the ViewController as the users swipe so I can partially fade some assets while the

相关标签:
6条回答
  • 2020-12-14 18:29

    UIPageViewController scroll doesn't work like normal scrollview and you can't get scrollView.contentOffset like other scrollViews.

    so here is a trick to get what's going on when user scrolls :

    first you have to find scrollview and set delegate to current viewController like other answers said.

    class YourViewController : UIPageViewController {
    
        var startOffset = CGFloat(0) //define this
    
        override func viewDidLoad() {
             super.viewDidLoad()
    
             //from other answers   
             for v in view.subviews{
                 if v is UIScrollView {
                     (v as! UIScrollView).delegate = self
                 }
             }
         }
    
        .
        .
        .
    }
    
    extension YourViewController : UIScrollViewDelegate{
    
        func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
    
            startOffset = scrollView.contentOffset.x
        }
    
        public func scrollViewDidScroll(_ scrollView: UIScrollView) {
    
            var direction = 0 //scroll stopped
    
            if startOffset < scrollView.contentOffset.x {
                direction = 1 //going right
            }else if startOffset > scrollView.contentOffset.x {
                direction = -1 //going left
            }
    
            let positionFromStartOfCurrentPage = abs(startOffset - scrollView.contentOffset.x)
            let percent = positionFromStartOfCurrentPage /  self.view.frame.width
    
            //you can decide what to do with scroll
        }
    
    }
    
    0 讨论(0)
  • 2020-12-14 18:31

    Similar to Christian's answer but a bit more Swift-like (and not unnecessarily continuing to loop through view.subviews):

    for view in self.view.subviews {
        if let view = view as? UIScrollView {
            view.delegate = self
            break
        }
    }
    
    0 讨论(0)
  • 2020-12-14 18:33

    You can search for the UIScrollView inside your UIPageViewController. To do that, you will have to implement the UIScrollViewDelegate.

    After that you can get your scrollView:

    for v in pageViewController.view.subviews{
        if v.isKindOfClass(UIScrollView){
            (v as UIScrollView).delegate = self
        }
    }
    

    After that, you are able to use all the UIScrollViewDelegate-methods and so you can override the scrollViewDidScroll method where you can get the scrollPosition:

    func scrollViewDidScroll(scrollView: UIScrollView) {
       //your Code
    }
    

    Or if you want a one-liner:

    let scrollView = view.subviews.filter { $0 is UIScrollView }.first as! UIScrollView
    scrollView.delegate = self
    
    0 讨论(0)
  • 2020-12-14 18:35
    var pageViewController: PageViewController? {
        didSet {
            pageViewController?.dataSource = self
            pageViewController?.delegate = self
            scrollView?.delegate = self
        }
    }
    
    lazy var scrollView: UIScrollView? = {
        for subview in pageViewController?.view?.subviews ?? [] {
            if let scrollView = subview as? UIScrollView {
                return scrollView
            }
        }
        return nil
    }()
    
    extension BaseFeedViewController: UIScrollViewDelegate {
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
    
        let offset = scrollView.contentOffset.x
        let bounds = scrollView.bounds.width
        let page = CGFloat(self.currentPage)
        let count = CGFloat(viewControllers.count)
        let percentage = (offset - bounds + page * bounds) / (count * bounds - bounds)
    
        print(abs(percentage))
    }
    }
    
    0 讨论(0)
  • 2020-12-14 18:47

    To make the code as readable and separated as possible, I would define an extension on UIPageViewController:

    extension UIPageViewController {
      var scrollView: UIScrollView? {
        view.subviews.first(where: { $0 is UIScrollView }) as? UIScrollView
      }
    }
    

    It's quite easy to set yourself as the delegate for scroll view events, as so:

    pageViewController.scrollView?.delegate = self
    
    0 讨论(0)
  • 2020-12-14 18:50

    As of iOS 13, the UIPageViewController seems to reset the scrollview's contentOffset once it transitions to another view controller. Here is a working solution:

    1. Find the child scrollView and set its delegate to self, as other answers suggested
    2. Keep track of the current page index of the pageViewController:
    var currentPageIndex = 0
    // The pageViewController's viewControllers
    let orderredViewControllers: [UIViewController] = [controller1, controller2, ...]
    
    pageViewController.delegate = self
    
    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
        guard completed, let currentViewController = pageViewController.viewControllers?.first else { return }
        currentPageIndex = orderredViewControllers.firstIndex(of: currentViewController)!
    }
    
    1. Get the progress that ranges from 0 to 1
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let contentOffsetX = scrollView.contentOffset.x
        let width = scrollView.frame.size.width
        let offset = CGFloat(currentPageIndex) / CGFloat(orderredViewControllers.count - 1)
        let progress = (contentOffsetX - width) / width + offset
    }
    
    0 讨论(0)
提交回复
热议问题