Tom Söderlund
Tom Söderlund

Reputation: 4747

Customizing navigation behavior of UIPageViewController

I'd like to customize the navigation behavior of UIPageViewController; specifically I'd like to navigate to different pages based on where on the screen the user drags her/his finger. Any pointers on where to start?

Upvotes: 0

Views: 431

Answers (1)

rob mayoff
rob mayoff

Reputation: 385670

The page view controller's curl navigation is triggered by a UIPanGestureRecognizer and UITapGestureRecognizer. You can find these in the page view controller's gestureRecognizers property.

In your pageViewController:viewControllerBeforeViewController: method and your pageViewController:viewControllerAfterViewController: method, you can ask the pan gesture recognizer for its location in the page view controller's view, and use that to decide where to navigate. You would probably want to actually delegate the decision to the currently-displayed view controller.

static UIPanGestureRecognizer *panRecognizerOfPageViewController(UIPageViewController *pageViewController) {
    for (id recognizer in pageViewController.gestureRecognizers) {
        if ([recognizer isKindOfClass:[UIPanGestureRecognizer class]])
            return recognizer;
    }
    return nil;
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
    viewControllerBeforeViewController:(UIViewController *)vc
{
    DetailViewController *dvc = (DetailViewController *)vc;
    UIPanGestureRecognizer *panner = panRecognizerOfPageViewController(pageViewController);
    CGPoint point = [panner locationInView:dvc.view];
    return [dvc priorViewControllerWithPoint:point];
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
    viewControllerAfterViewController:(UIViewController *)vc
{
    DetailViewController *dvc = (DetailViewController *)vc;
    UIPanGestureRecognizer *panner = panRecognizerOfPageViewController(pageViewController);
    CGPoint point = [panner locationInView:dvc.view];
    return [dvc nextViewControllerWithPoint:point];
}

In my testing, I only have to ask the pan gesture recognizer for its location. When the gesture is a pan, both recognizers are in state “Possible”. When the gesture is a tap, the pan recognizer is in state “Failed” but it reports the location of the tap touch anyway.

Of course, this isn't documented behavior. If you don't want to rely on it, you need to get access to the current touch's location some other way. I would probably just use a subclass of UIWindow and override its sendEvent: to save the most recent touch event in an instance variable for easy access.

Upvotes: 1

Related Questions