Custom Page Control For UIPageViewController
I've found that the delegate methods from UIPageViewController don't give me enough information to create a perfect page indicator control. pageViewController:willTransitionToViewControllers:
is too early and pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:
gets called after the animation is finished which is too late to update a page indicator.
The best time to update a page indicator is either fluently during the transition or switch to the next / previous "dot" as soon as 50% is reached. This can be accomplished by accessing the UIPageViewControllers scroll view and becoming its delegate. Hacky, yes, so be cautious.
for (UIView *v in pageViewController.view.subviews) {
if ([v isKindOfClass:[UIScrollView class]]) {
((UIScrollView *)v).delegate = self;
}
}
-
#pragma mark - UIPageViewControllerDelegate
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {
NSInteger index = [_viewControllers indexOfObject:pageViewController.viewControllers.firstObject];
[_pageIndicatorView setCurrentIndex:index];
_currentIndex = index;
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat offset = scrollView.contentOffset.x - self.view.frame.size.width;
if (offset > 0 && _currentIndex < _viewControllers.count) {
// forward
if (offset > self.view.frame.size.width / 2) {
[_pageIndicatorView setCurrentIndex:_currentIndex+1];
} else {
[_pageIndicatorView setCurrentIndex:_currentIndex];
}
} else if (offset < 0 && _currentIndex > 0) {
// backward
if (offset < -(self.view.frame.size.width / 2)) {
[_pageIndicatorView setCurrentIndex:_currentIndex-1];
} else {
[_pageIndicatorView setCurrentIndex:_currentIndex];
}
}
}
_pageIndicatorView is my custom pag control, nothing fancy.
As you can see we additionally use the didFinishAnimating
delegate method to handle the falling back whne the user lets go during a transition.