19

I have a UIPageViewController and I just can not figure out how to know to what direction the user turned the page so i can set the page count appropriately.

Thanks Shani

shannoga
  • 19,649
  • 20
  • 104
  • 169

6 Answers6

32

As Hejazi said

After a gesture-driven transition completes this delegate method is called:

pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:

The part that should be clarified is that completed will be YES if the page was fully turned and will be NO if the page did not actually turn. The NO case happens, for example, when the user just pulls up the corner of the page and then puts it back down without flipping the page.

This is the concept you will want to implement:

- (void)pageViewController:(UIPageViewController *)pvc didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
    // If the page did not turn
    if (!completed)
    {
        // You do nothing because whatever page you thought 
        // the book was on before the gesture started is still the correct page
        return;
    }

    // This is where you would know the page number changed and handle it appropriately
    // [self sendPageChangeNotification:YES];
}
roff
  • 502
  • 3
  • 5
  • Also note that the page may not have actually changed even if the event is finished. The user may partially turn a page but not far enough to change the page, then the animation will take them back to the page that they were already on. – diadyne Oct 19 '12 at 19:46
  • 1
    @diadyne there are two BOOLs involved here- 'finished' will be true if the event finished but as chrisofflive said, 'completed' will indicate whether or not the user completed the page turn. – todd412 Apr 08 '14 at 19:58
  • This answer gets me closer to the solution. With your answer combines with which `index` that is the next that it *will* transition to solve the problem. See this [answer](http://stackoverflow.com/a/27576378/571227) too on how to know the next index it will transition to. – haxpor Sep 03 '15 at 11:05
7

After a gesture-driven transition completes this delegate method is called:

pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:

So by comparing the previousViewControllers parameter and pageViewController.viewControllers you can know the direction.

Hejazi
  • 16,587
  • 9
  • 52
  • 67
  • hi Hejazi, I'm comparing the two arrays with if([previousViewControllers isEqualToArray:pvc.viewControllers]) and i always get false (when I turn the page to the right or to the left), am I doing something wrong ? – Grace Mar 20 '13 at 08:11
  • `previousViewControllers` always contains single item, it can't be used to distinguish between directions. – lambdas Feb 01 '14 at 11:07
  • @lambdas As long as you know the page number associated with a given view controller, you can figure out the direction by checking the previous view controller(s) and current view controller(s). – Hejazi Feb 03 '14 at 12:02
3

The 'Page-Based Application' template provide these 2 methods :

- (NSUInteger)indexOfViewController:(DataViewController *)viewController; 

a method for finding index given a view controller

- (DataViewController *)viewControllerAtIndex:(NSUInteger)index

a method for instantiating a view controller given an index.

For making the correct animation, you need to know the index of your current view controller. The page-based template methods are perfect fit for that. Then, you simply compare your 'jump to' index and your 'current' index.

Here's some code to get the idea :

- (void)jumpToPage:(NSInteger)page {    
   // find current index
   DataViewController *currentViewController = (DataViewController *)[self.pageViewController.viewControllers lastObject];
   NSUInteger index = [self indexOfViewController:currentViewController];

   // choosing the correct direction
   // if the 'current' is smaller than the 'jump to' page, then choose forward
   // vice versa
   UIPageViewControllerNavigationDirection direction;
   if (index < page) {
       direction = UIPageViewControllerNavigationDirectionForward;
   } else {
       direction = UIPageViewControllerNavigationDirectionReverse;
   }

   // choose view controllers according to the orientation
   NSArray *viewControllers;
   if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
       DataViewController *rightViewController = [self viewControllerAtIndex:page];
       viewControllers = [NSArray arrayWithObject:rightViewController];
   } else {
       DataViewController *rightViewController = [self viewControllerAtIndex:page];
       DataViewController *leftViewController = [self viewControllerAtIndex:page-1];
       viewControllers = [NSArray arrayWithObjects:leftViewController, rightViewController, nil];
   }

   // fire the method which actually trigger the animation
   [self.pageViewController setViewControllers:viewControllers 
                                     direction:direction 
                                      animated:YES 
                                    completion:nil];
}
Ikhsan Assaat
  • 900
  • 1
  • 9
  • 23
  • I am talking about a situation when the animation is triggered by the native gesture recognizers. – shannoga Jan 13 '12 at 07:25
  • Have you set your pageviewcontroller's data source? There are two methods that you should implement, `– pageViewController:viewControllerBeforeViewController:` called when the page is flipped backward, `– pageViewController:viewControllerAfterViewController:` called when the page is flipped forward. Is this what are you trying to find? I don't understand your question thoroughly, maybe you should explain your problem in more detail. – Ikhsan Assaat Jan 13 '12 at 09:07
  • I am using those methods. the thing is that I need to update a variable that hold the page number. I have an Array of objects that I need to assign to the visible controller and I need to know what is the page number so I can get the correct object. To do that I need to know if the user went back or forward so I can update the page number correctly. – shannoga Jan 13 '12 at 09:10
2

You could add a "pageIndex" property to your view controllers that serve as the pages. IOW, when you create the view controllers for viewControllerBeforeViewController & viewControllerAfterViewController (or when you call setViewControllers), store a pageIndex in those view controllers that you can then reference whenever you need to know the index.

Mark Krenek
  • 4,889
  • 3
  • 25
  • 17
1

great answers for page controller handling. I found that the view controller that was added as a page will call viewWillAppear as the user slides the page into view and will also call viewDidAppear upon completion.

cynistersix
  • 1,215
  • 1
  • 16
  • 30
0

When the user turns a page the UIPageViewController's setViewControllers: method will be called. This method receives an argument of type UIPageViewControllerNavigationDirection that will give you the information you need.

jonkroll
  • 15,682
  • 4
  • 50
  • 43
  • 15
    At least on iOS 6, `-setViewControllers:direction:animated:completion:` doesn't get called if the transition was gesture-initiated. I just tried it. – jrc Feb 25 '13 at 21:04