PageViewController delegate functions called twice

2019-01-15 08:08发布

问题:

I am working with UIPageViewController , to make a product tour for my application.

I followed this link http://www.appcoda.com/uipageviewcontroller-tutorial-intro/

I am doing is simple task of changing backgound color of my "root VC" on swipe, based on the index value I get, but as the delegate functions are called twice, my index value is not correct and because of that, I am not able to get it right, below is my code

#import "APPViewController.h"
#import "APPChildViewController.h"

@interface APPViewController ()

@end

@implementation APPViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];

    self.pageController.dataSource = self;
    [[self.pageController view] setFrame:CGRectMake(0, 0, 320, 500)];

    APPChildViewController *initialViewController = [self viewControllerAtIndex:0];

    NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];

    [self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];

    [self addChildViewController:self.pageController];
    [[self view] addSubview:[self.pageController view]];
    [self.pageController didMoveToParentViewController:self];

}

- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.

}

- (APPChildViewController *)viewControllerAtIndex:(NSUInteger)index {

    APPChildViewController *childViewController = [[APPChildViewController alloc] initWithNibName:@"APPChildViewController" bundle:nil];
    childViewController.index = index;
    childViewController.view.backgroundColor = [UIColor clearColor];

    if(index == 0)
    {
          self.view.backgroundColor = [UIColor redColor];
     }

    if(index == 1)
    {
          self.view.backgroundColor = [UIColor blueColor];
     }

    if(index == 2)
    {
          self.view.backgroundColor = [UIColor greenColor];
     }


    return childViewController;

}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {

    NSUInteger index = [(APPChildViewController *)viewController index];

    if (index == 0) {
        return nil;
    }

    // Decrease the index by 1 to return
    index--;

   return [self viewControllerAtIndex:index];

}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {

    NSUInteger index = [(APPChildViewController *)viewController index];

    index++;

    if (index == 3) {
        return nil;
    }

   return [self viewControllerAtIndex:index];

}

- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController {
    // The number of items reflected in the page indicator.
    return 3;
}

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController {
    // The selected item reflected in the page indicator.
    return 0;
}

Please help me out, I am not getting where I am going wrong

Regards Ranjit

回答1:

After looking for a lot.

I receive that:

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController;
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController;

2 functions use to get pageViewController behind or in front of current pageViewController.

I thinks it's difficult to get current pageViewController

My suggestion:

In UIPageViewControllerDelegate, it have a function :

 - (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers;

This function to give you a pendingViewControllers array and this's current pageViewController array. So you can implement like that :

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers
{


if([pendingViewControllers count]>0)
  {
     NSUInteger index =[(APPChildViewController*)[pendingViewControllers objectAtIndex:0] index];

    if(index == 0)
    {
        self.view.backgroundColor = [UIColor redColor];
    }

    if(index == 1)
    {
        self.view.backgroundColor = [UIColor blueColor];
    }

    if(index == 2)
    {
        self.view.backgroundColor = [UIColor greenColor];
    }


  }
}

In viewDidLoad, you add :

    self.pageController.delegate = self;

    self.view.backgroundColor = [UIColor redColor]; //set first background.

In 'APPViewController.h' you sure add:

@interface APPViewController : UIViewController<UIPageViewControllerDataSource,UIPageViewControllerDelegate>

Remember : remove this code (in 'viewControllerAtIndex' function)

if(index == 1)
{
    self.view.backgroundColor = [UIColor redColor];
}

if(index == 2)
{
    self.view.backgroundColor = [UIColor blueColor];
}

if(index == 3)
{
    self.view.backgroundColor = [UIColor greenColor];
}

Let's me know if you have any questions.



回答2:

Replace these two methods and compile,

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {

    NSUInteger index = [(APPChildViewController *)viewController index];
    if (index == 0)
    {
        self. view.backgroundColor = [UIColor redColor];
        return nil;
    }

    if(index == 1)
    {
        self.view.backgroundColor = [UIColor blueColor];
    }

    if(index == 2)
    {
        self.view.backgroundColor = [UIColor greenColor];
    }
    if(index == 3)
    {
        self.view.backgroundColor = [UIColor brownColor];
    }
    /*if(index == 4)
    {
        self.view.backgroundColor = [UIColor whiteColor];
    }*/

    // Decrease the index by 1 to return
    index--;

    return [self viewControllerAtIndex:index];

}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {

    NSUInteger index = [(APPChildViewController *)viewController index];
    /*if(index == 0)
    {
        self.view.backgroundColor = [UIColor redColor];
    }*/
    if(index == 1)
    {
        self.view.backgroundColor = [UIColor blueColor];
    }

    if(index == 2)
    {
        self.view.backgroundColor = [UIColor greenColor];
    }
    if(index == 3)
    {
        self.view.backgroundColor = [UIColor brownColor];
    }
    if(index == 4)
    {
        self.view.backgroundColor = [UIColor whiteColor];
        return nil;
    }

    /*if (index == 5) {
        return nil;
    }*/
    index++;

    return [self viewControllerAtIndex:index];

}

and add this in the end of - (void)viewDidLoad {

self.view.backgroundColor = [UIColor redColor];



回答3:

I faced the same issue and finally figured out the cause . The delegate methods are called twice when the the Transition style for the page view controller is set to " Page Curl".

When the transition style is set to "Page Curl", the action is like turning a page in a book. You turn one page and the page number gets incremented by 2. Applying the same concept for the page view controller, 2 view controllers are transitioned for Page Curl style: one is the view controller you see and the other view controller is on the other side of the curled view.

Change the transition style to "Scroll" and you can get rid of the problem

This can be done from storyboard in the attribute inspector as follows: check image

You can also change the same by code by setting the UIPageViewController.transitionStyle property to UIPageViewControllerTransitionStyleScroll.

Hope it helps