Get scroll position of UIPageViewController - Printable Version +- 0Day Forums (https://0day.red) +-- Forum: Coding (https://0day.red/Forum-Coding) +--- Forum: Swift (https://0day.red/Forum-Swift) +--- Thread: Get scroll position of UIPageViewController (/Thread-Get-scroll-position-of-UIPageViewController) |
Get scroll position of UIPageViewController - ultrasound615963 - 07-19-2023 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 view is transitioning to the next `UIViewController`. The delegate and datasource methods of `UIPageViewController` don't seem to provide any access to this, and internally I'm assuming that the `UIPageViewController` must be using a scroll view somewhere, but it doesn't seem to directly subclass it so I'm not able to call func scrollViewDidScroll(scrollView: UIScrollView) { } I've seen some other posts suggestion to grab a reference to the `pageViewController!.view.subviews` and then the first index is a scrollView, but this seems *very* hacky. I'm wondering if there is a more standard way to handle this. RE: Get scroll position of UIPageViewController - martinelli55 - 07-19-2023 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)! } ``` 3. 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 } ``` RE: Get scroll position of UIPageViewController - deposition168 - 07-19-2023 To make the code as readable and separated as possible, I would define an extension on `UIPageViewController`: ```swift 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 ``` RE: Get scroll position of UIPageViewController - consenting460514 - 07-19-2023 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)) } } RE: Get scroll position of UIPageViewController - Madelaine512575 - 07-19-2023 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 } } RE: Get scroll position of UIPageViewController - insufficient677 - 07-19-2023 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 RE: Get scroll position of UIPageViewController - proportioned568302 - 07-19-2023 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 } } |