I found a weird issue with the two UIPageViewControllerDataSource
methods: the first time I enter the page view controller scene and drag on the content of the controller, no matter what the dragging direction is, both of the data source methods get called. I suppose that when I'm at the first page and drag to the right, which means that there is no more page before the first page, neither of the methods should get called. And if I drag to the left, only the after method should get called.
I followed this post to set up the view controllers (except that I do not have a separate page view controller on the storyboard. I used the traditional [UIPAgeViewController alloc] init]
method to instantiate the controller). Below is my code:
For the view controller that actually displays the content of the page view controller (only the relevant part of viewDidLoad
is shown):
- (void)viewDidLoad
{
// initialize page view controller
_pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageViewController.delegate = self;
self.pageViewController.dataSource = self;
// set up the initial scene of the page view controller
UIViewController *viewController = [self viewControllerAtIndex:0];
[self.pageViewController setViewControllers:@[viewController]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
// adjust the size of the page view controller, -44 to show the buttons at the bottom
self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 44);
// display the content of the page view controller
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = ((PWCPageContentViewController *)viewController).index;
if (index == 0 || index == NSNotFound) {
return nil;
}
--index;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = ((PWCPageContentViewController *)viewController).index;
if (index == self.numberOfPages - 1 || index == NSNotFound) {
return nil;
}
++index;
return [self viewControllerAtIndex:index];
}
- (PWCPageContentViewController *)viewControllerAtIndex:(NSUInteger)index
{
PWCPageContentViewController *viewController =
[self.storyboard instantiateViewControllerWithIdentifier:@"PageContentViewController"];
viewController.index = index;
NSString *text = [self.notes getNoteAtIndex:index];
[viewController.textView setText:text];
return viewController;
}
For PWCPageContentViewController.h:
#import <UIKit/UIKit.h>
@class PWCNotes;
@interface PWCPageContentViewController : UIViewController <UITextViewDelegate>
@property NSUInteger index;
@property (weak, nonatomic) IBOutlet UITextView *textView;
- (void)dismissKeyboard;
@end
For PWCPageContentViewController.m:
#import "PWCPageContentViewController.h"
@interface PWCPageContentViewController ()
@end
@implementation PWCPageContentViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.textView.delegate = self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)dismissKeyboard
{
if ([self.textView isFirstResponder]) {
// dismiss the keyboard when hitting save
[self.textView resignFirstResponder];
}
}
@end
So is this a known issue or am I missing something?
Solution to this problem in Swift:
I encountered the bug when I used more than 3 UIPageViewController
(try with 4 UIPageViewController
for example, using the @Rashad's snippet). The problem came from a missing and non implemented optional UIPageViewControllerDelegate's method, which drove the UIPageControl crazy and unstable.
Please find the particular method which fixes the bug below:
/*
Optional UIPageViewControllerDelegate method
Sent when a gesture-initiated transition ends. The 'finished' parameter indicates whether
the animation finished, while the 'completed' parameter indicates whether the transition completed or bailed out (if the user let go early).
*/
func pageViewController(pageViewController: UIPageViewController,
didFinishAnimating finished: Bool,
previousViewControllers: [AnyObject],
transitionCompleted completed: Bool)
{
// Turn is either finished or aborted
if (completed && finished) {
let currentDisplayedViewController = self.pageViewController!.viewControllers[0] as! ContentViewController
self.pageControl.currentPage = currentDisplayedViewController.index
}
}
If you want to get the full working project, please find the Github link below:
(Github link of the project)
UIPageViewController
uses these bellow method for getting the back and front ViewController.
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController;
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController;
Though its weird but yes its a known issue. Every time it calls Before and After method to get VC. If there is no next VC then it returns nil
and if there is no previous VC the datasourceDelegate
return nil, otherwise it return the index of VC.
In UIPageViewControllerDelegate
, there is a function named :
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers;
Look at this it might help to get the current or next/previous viewcontroller from pendingViewControllers
array.
Hope this helps.. :)
So as @Rashad suggested, pageViewController:willTransitionToViewControllers:
isn't messed up. It is called exactly once when you transition to the previous/next view controller (in case that the previous/next view controller is not nil
). This also applies to pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:
, which is called exactly once when the animation finishes.
So if you want to do any index-based things and you want to get the correct index for the upcoming view controllers, or you want to get the correct view controller, consider using these two methods as a workaround for now.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With