Progress of UIPageViewController

Since I thought that the functionality of scrolling would stay forever, but that the internal implementation may change to something other than a scroll view, I found the solution below (I haven't tested this very much, but still)

NSUInteger offset = 0;
UIViewController * firstVisibleViewController;
while([(firstVisibleViewController = [self viewControllerForPage:offset]).view superview] == nil) {
  ++offset;
}
CGRect rect = [[firstVisibleViewController.view superview] convertRect:firstVisibleViewController.view.frame fromView:self.view];
CGFloat absolutePosition = rect.origin.x / self.view.frame.size.width;
absolutePosition += (CGFloat)offset;

(self is the UIPageViewController here, and [-viewControllerForPage:] is a method that returns the view controller at the given page)

If absolutePosition is 0.0f, then the first view controller is shown, if it's equal to 1.0f, the second one is shown, etc... This can be called repeatedly in a CADisplayLink along with the delegate methods and/or UIPanGestureRecognizer to effectively know the status of the current progress of the UIPageViewController.

EDIT: Made it work for any number of view controllers


in SWIFT to copy paste ;) works perfect for me

extension UIPageViewController: UIScrollViewDelegate {

    public override func viewDidLoad() {
        super.viewDidLoad()

        for subview in view.subviews {
            if let scrollView = subview as? UIScrollView {
                scrollView.delegate = self
            }
        }
    }

   public func scrollViewDidScroll(_ scrollView: UIScrollView) {
       let point = scrollView.contentOffset
       var percentComplete: CGFloat
       percentComplete = abs(point.x - view.frame.size.width)/view.frame.size.width
       print("percentComplete: ",percentComplete)
   }
}

At last I found out a solution, even if it is probably not the best way to do it:

I first add an observer on the scrollview like this:

// Get Notified at update of scrollview progress
NSArray *views = self.pageViewController.view.subviews;
UIScrollView* sW = [views objectAtIndex:0];
[sW addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:NULL];

And when the observer is called:

NSArray *views = self.pageViewController.view.subviews;
UIScrollView* sW = [views objectAtIndex:0];
CGPoint point = sW.contentOffset;

float percentComplete;
//iPhone 5
if([ [ UIScreen mainScreen ] bounds ].size.height == 568){
    percentComplete = fabs(point.x - 568)/568;

} else{
//iphone 4
    percentComplete = fabs(point.x - 480)/480;
}
NSLog(@"percentComplete: %f", percentComplete);

I'm very happy that I found this :-)