Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 278 Vote(s) - 3.45 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Get scroll position of UIPageViewController

#1
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.
Reply

#2
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
}
```
Reply

#3
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
```
Reply

#4

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))
}
}
Reply

#5
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
}

}
Reply

#6
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
Reply

#7
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
}
}

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through