UIPageViewController: get the currentPage

2019-03-14 17:22发布

问题:

I have been struggling with this issue for the last few days and after all this juggling I have figured out that all I need is the current Index from the datasource method to update with current visible page number

I have this UIPageViewController datasource method and I need to use the current index to get the current visible page for delegate method previousViewControllers transitionCompleted:(BOOL)completed

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
   viewControllerAfterViewController:(UIViewController *)viewController { 
    NSString *path = [[NSBundle mainBundle] pathForResource:@"pages" ofType:@"pdf"];

    NSURL *pdfurl = [NSURL fileURLWithPath:path];
    PDFDocument = CGPDFDocumentCreateWithURL((__bridge CFURLRef)pdfurl);

    contentViewController = [[ContentViewController alloc] initWithPDFAtPath:path];

    currentIndex = [modelArray indexOfObject:[(ContentViewController *)viewController page]];

    if (currentIndex == totalPages - 1) {  
        return nil;
    }

    contentViewController.page = [modelArray objectAtIndex:currentIndex + 1];

    return contentViewController;
}

I'm confused about how to write the current index statement from datasource method into delegate method to update current visible page.

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{

    if (!completed)
    {
        return;
    }

    //currentIndex = [[self.pageViewController.viewController lastObject]];  
    currentIndex = [self indexOfObject:contentViewController];

    [self displaycurrentIndex:currentIndex];
    //self.pageControl.currentPage = currentIndex;
}

How can I correct this?

回答1:

It looks like you should be able to get the current index with:

ContentViewController *viewController = [self.pageViewController.viewControllers lastObject];
currentIndex = [modelArray indexOfObject:[viewController page]];


回答2:

for swift:

func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool){
        let pageContentViewController = pageViewController.viewControllers![0] as! ViewController
        let index = pageContentViewController.pageIndex

}


回答3:

if you implement ModelController (as in Apple example), use it's method indexOfViewController

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {
    myDataViewController *currentView = [pageViewController.viewControllers objectAtIndex:0];
    NSInteger currentIndex = [_modelController indexOfViewController:currentView];
    [self displayPageNumber:currentIndex];
}


回答4:

Implement Delegate Method

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{
        NSLog(@"Current Page = %@", pageViewController.viewControllers);

        UIViewController *currentView = [pageViewController.viewControllers objectAtIndex:0];

             if ([currentView isKindOfClass:[FirstPageViewController class]]) {
                 NSLog(@"First View");
            }
            else if([currentView isKindOfClass:[SecondPageViewController class]]){
                 NSLog(@"Second View");
            }
            else if([currentView isKindOfClass:[ThirdViewController class]]){
                  NSLog(@"Third View");
            }
 }

//pageViewController.viewControllers always return current visible View ViewController



回答5:

I am facing the same issue on pageViewController, everytime i swipe my pageViewController it calls my delegate twice and am not able to find the issue. And my array is dynamic so i want the proper index value from pageController. First of all set the delegate of your pageViewController. Like this :-

self.pageViewController.delegate = self;

And then add this delegate method to your class

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
if (completed) {
    NSInteger currentIndex = ((PageContentViewController *)self.pageViewController.viewControllers.firstObject).pageIndex;

    NSLog(@"%ld",(long)currentIndex);
}
}

PageContentViewController is the class where you are showing your data of pageViewController.

Run your project and if everything is working fine, you will get your index value. PageIndex is the Integer value for getting the current index. Hope it will helps you.

Thanks

Mandeep Singh



回答6:

To get the current index you'll have to do the following:

-(void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {


   NSUInteger index = [self.viewControllers indexOfObject: [pageViewController.viewControllers lastObject]];

   NSLog(@"INDEX: %lu",(unsigned long)index);

}


回答7:

I struggled with this too and none of the other solutions worked for me, but was finally able to solve it using a delegate method:

First in PageContentViewController.h Add the following property:

@property NSUInteger pageIndex;

Second create a delegate protocol in the PageContentViewController (not the PageViewController).

In PageContentViewController.h:

 @protocol PageContentDelegate <NSObject>

 - (void)sendBackPageIndex:(NSUInteger)index;

@end

@interface LKFPageContentViewController : (UIViewController)

@property (weak, nonatomic) id<LKFPageContentDelegate> delegate;
....
@end

Third in PageContentViewController.m perform delegate method in viewDidAppear

//Note that this must be done in viewDidAppear not viewDidLoad
- (void)viewDidAppear:(BOOL)animated {

[super viewDidAppear:YES];

[self.delegate sendBackPageIndex:self.pageIndex];

Fourth, in PageViewController.m implement the delegate method

#pragma mark - PageContentView delegate methods

- (void)sendBackPageIndex:(NSUInteger)index {

    //This is where you get your current page index
    NSUInteger currentPageIndex = index;
}

Fifth, in PageViewController.m make sure you pass the pageIndex value and set the delegate

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

    if (([self.arrayOfTitles count] == 0) || (index >= [self.arrayOfTitles count])) {
        return nil;
    }

    // Create a new view controller and pass suitable data.
    PageContentViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"PageContentViewController"];

    pageContentViewController.pageIndex = index;

    pageContentViewController.delegate = self;

    return pageContentViewController
}


回答8:

I have solved this problem like this:

* Parent View Controller (PageViewController) *

@interface MyParentPageViewController () <UIPageViewControllerDataSource>


@property (nonatomic, assign) NSUInteger currentPageIndex;

@end

@implementation MyParentPageViewController

- (void)viewDidLoad 
{
  [super viewDidLoad];

  MyChildViewController *rootChildViewController = [MyChildViewController controllerWithPageIndex:self.currentPageIndex];
  [self setViewControllers:@[rootChildViewController]
             direction:UIPageViewControllerNavigationDirectionForward
              animated:YES completion:nil];
  self.dataSource = self;
}

#pragma mark - Page View Controller DataSource
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController 
viewControllerAfterViewController:(MyChildViewController *)viewController
{
  if (viewController.pageIndex == self.sourceArray.count - 1) {
    return nil;
  }
  MyChildViewController *vc = [MyChildViewController controllerWithPageIndex:viewController.pageIndex + 1];
  return vc;
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(CHHomeDetailTableController *)viewController 
{
  if (viewController.pageIndex == 0) {
    return nil;
  }
  MyChilViewController *vc = [MyChildViewController controllerWithPageIndex:viewController.pageIndex - 1];
  return vc;
}


@end

* Child View Controller *

@implementation MyChildViewController
- (void)viewWillAppear
{
    MyParentPageViewController *parentPageViewController = (MyParentPageViewController *)self.parentViewController;
    parentViewController.currentPageIndex = self.pageIndex;
}
@end

For example, the parentPageViewController's currentPageIndex is 10 , or some other values, when your swipe right, parentViewController.currentPageIndex will be 9, if 0 , nothing happened; If you swipe left, parentPageViewController.currentPageIndex will be 11, if the showing controller.view is the last, nothing happened too.



回答9:

You can try this. This will give you current page.

    - (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
    UIViewController * viewController = [previousViewControllers lastObject];

    NSUInteger previousPage = [(PageContentViewController *)viewController index];

    NSUInteger currentPage = previousPage+1;
}


回答10:

This is how I determine the current page index whether the user swipes to the left or to the right and whether he changes his swipe direction gesture in the middle of swiping. Just make sure you have a pageIndex property in your view controller to store the index:

func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [UIViewController]) {
        let currentPageIndex = (pendingViewControllers.last! as! ViewController).pageIndex!
    }


回答11:

There is no nice way to do this but I think the most reliable way is to observe UIPageViewControllerDelegate calls:

var index: Int
var proposedViewController: UIViewController?

// MARK: UIPageViewControllerDelegate

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    guard let proposedViewController = proposedViewController,
        let index = myViewControllers?.index(of: proposedViewController) else {
            return
    }
    self.index = index
}

func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
    guard pendingViewControllers.count == 1,
        let proposedViewController = pendingViewControllers.first else {
        return
    }
    self.proposedViewController = proposedViewController
}


回答12:

My approach is quite simple:

  1. When the page (controller) is instantiated I pass in the page index, which at this point is known.

  2. Then in the delegate call below, iff the transition finished, I obtain the controller currently shown and cast it to my custom page class, before I fetch and update the currentPage with the associated page index.

To keep things simple I setup the data source and delegate to be the WalkThroughController which embeds the page view controller.

extension WalkThroughController: UIPageViewControllerDelegate {

    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {

        guard finished, let currentPageController = pageViewController.viewControllers?.last as? WalkThroughPageViewController else {
            return
        }

        self.currentPage = currentPageController.pageIndex
    }

}

The take away point is to set the page index of the pages when they are created in the data source. With this approach it is very straight forward to retrieve it later.