swalkner
swalkner

Reputation: 17329

UIPageViewController: pageViewController:spineLocationForInterfaceOrientation: not called

my spineLocationForInterfaceOrientation-method is not called; therefore, the spine is always on the left, but I would like to have it in the middle... what am I doing wrong?

if ([UIPageViewController class]) {
    self.pageViewController = [[UIPageViewController alloc]
        initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
        navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
    self.pageViewController.view.backgroundColor = [UIColor redColor];
    self.pageViewController.delegate = self;

    NotesPageController *notesPageController = [[NotesPageController alloc]
        initWithNibName:@"NotesPageController" bundle:nil];
    NSArray *pageViewControllers = [NSArray arrayWithObjects:notesPageController, nil];
    [self.pageViewController setViewControllers:pageViewControllers
        direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];

    self.pageViewController.dataSource = self;

    [self addChildViewController:self.pageViewController];

    [self.navigationController pushViewController:self.pageViewController animated:NO];
}

Thanks a lot!

Upvotes: 3

Views: 15631

Answers (4)

Puran
Puran

Reputation: 994

Here's what worked for me. I used the default project which is generated by apple page view template. But when I was using it inside navigation controller it was not displaying the spine properly so had to modify the initialization code which can be called from viewDidLoad method.

- (void)initializePageViewController
{
    int numberOfPagesPerScreen = 1;
    if(UIInterfaceOrientationIsPortrait(self.interfaceOrientation))
      numberOfPagesPerScreen = 1;
    else
      numberOfPagesPerScreen = 2;       

    // for two-page layouts, we'll need to specify the spine location
    NSDictionary *pageViewOptions = nil;
    if(numberOfPagesPerScreen == 2)
      pageViewOptions = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInteger:UIPageViewControllerSpineLocationMid], UIPageViewControllerOptionSpineLocationKey, nil];  

    self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:pageViewOptions];
    self.pageViewController.delegate = self;

    NSMutableArray *pageViewControllers = [NSMutableArray array];

    for(int pageViewIdx = 0; pageViewIdx < numberOfPagesPerScreen; pageViewIdx++) {
      MyPageViewController *pageController = [self.modelController viewControllerAtIndex:pageViewIdx storyboard:self.storyboard];
      [pageViewControllers addObject:pageController];
    }
    [self.pageViewController setViewControllers:pageViewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];

    self.pageViewController.dataSource = self.modelController;

    [self addChildViewController:self.pageViewController];
    [self.view addSubview:self.pageViewController.view];

    // Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages.
    CGRect pageViewRect = self.view.bounds;
    pageViewRect = CGRectInset(pageViewRect, 40.0, 40.0);
    self.pageViewController.view.frame = pageViewRect;

    [self.pageViewController didMoveToParentViewController:self];

    // Add the page view controller's gesture recognizers to the book view controller's view so that the gestures are started more easily.
    self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
}

Upvotes: 1

Andreas
Andreas

Reputation: 123

sample code for the answer provided by Totumus Maximus

NSDictionary *options =  [NSDictionary dictionaryWithObject:
 [NSNumber numberWithInteger:UIPageViewControllerSpineLocationMid]
                            forKey: UIPageViewControllerOptionSpineLocationKey];    
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:options];

Upvotes: 2

Dylan
Dylan

Reputation: 728

Do you have the view controller that contains the code above properly inserted into the view controller hierarchy? Start by setting UIWindow.rootViewController and then call addChildViewController: on every controller in the hierarchy. That's what was necessary for me to get the rotation forwarding and the spine function called when retrofitting an iOS4 app.

Edit: I've discovered there is more to it than this. Apple has made this class rather difficult to use. The problem is if you want to create the UIPageViewController at a different time from when you first call setViewControllers. Most likely, the controller that contains the UIPageViewController is going to create it in init or viewDidLoad. But the true orientation isn't know at this point because apps are always started in portrait and then are sent rotation notifications if it's really in landscape. So, at the point most apps are going to create the UIPageViewController they don't know where the spine should be located.

Apple's sample calls setViewControllers at the same time as initWithTransitionStyle. This works in a trivial example like Apple's but most apps are probably going to dynamically load the content at a later time. If you haven't set any view controllers, then spineLocationForInterfaceOrientation isn't called.

So now you're stuck if you've already created the UIPageViewController with initWithTransitionStyle. You can't set the spine location and you have to insert exactly the correct number of view controllers for how you initialized the class when you didn't know the true orientation. If you set the wrong number of view controllers, it unhelpfully displays nothing on screen.

I see two possible solutions:

  1. Always insert a dummy UIViewController right after calling initWithTransitionStyle. Having a view controller in there will cause it to respond to rotation events and spineLocationForInterfaceOrientation will be called.

  2. Delay the create of the UIPageViewController until you are ready to set the actual content and the true orientation is known. This is what I chose.

Upvotes: 12

Totumus Maximus
Totumus Maximus

Reputation: 7573

Have you tried setting the spine property manually?

To set the spine location, wrap one of these constants in an NSNumber object and set it as the value for the UIPageViewControllerOptionSpineLocationKey key in the options dictionary passed to the initWithTransitionStyle:navigationOrientation:options: method.

Ref: http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIPageViewControllerClassReferenceClassRef/UIPageViewControllerClassReference.html

Upvotes: 5

Related Questions