Ariel Zehao Zhang
Ariel Zehao Zhang

Reputation: 564

iOS6 autorotation - UIPageViewController

My UI structure:

UINavigationController
--UIViewController(first)
 |
 |Modal 
 |
 V 
UINavigationController (subclass)
--UIViewController (contains UIPageViewController)

For iOS6 new autorotation, I created a subclass of UINavigationController and added:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}

- (BOOL)shouldAutorotate
{
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

Only want keep the orientation is portrait.

And I initialize UIPageViewController like:

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

    PageDataViewController *startingViewController = [self viewControllerAtIndex:start storyboard:self.storyboard];

    NSArray *viewControllers = [NSArray arrayWithObject:startingViewController];
    [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];

    self.pageViewController.dataSource = self;

    [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;
    self.pageViewController.view.frame = pageViewRect;

    [self.pageViewController didMoveToParentViewController:self];

Then I perform the Modal segue, if the first UIViewController is portrait, the pageViewController works, but if the first UIViewController is landscape, I always got exception:

* Assertion failure in -[UIPageViewController willAnimateRotationToInterfaceOrientation:duration:], /SourceCache/UIKit_Sim/UIKit-2372/UIPageViewController.m:945 Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'No view controllers' ** First throw call stack: (0x2a5e012 0x19bae7e 0x2a5de78 0x1450f35 0xd75974 0x9f12b4 0x9f13ea 0x9e4c32 0x9f1372 0x9f13ea 0x9e4c32 0x9f1372 0x9f1751 0x93a1a6 0xbee5f9 0x9ec4f3 0x9ec777 0x9ec7b7 0xd57fe2 0xd49ad9 0xd49b54 0x9b1899 0x9b1b3d 0x13b8e83 0x2a1d376 0x2a1ce06 0x2a04a82 0x2a03f44 0x2a03e1b 0x2c967e3 0x2c96668 0x90265c 0xea7d 0x2685 0x1) libc++abi.dylib: terminate called throwing an exception

Upvotes: 2

Views: 3114

Answers (4)

Haresh Ghatala
Haresh Ghatala

Reputation: 1

I have "fixed" the problem, by setting view controllers to UIPageViewController in viewWillAppear: again, because when this method is called, spine location for page view controller is correct and based on this information i set one, or two pages (view controllers)

Upvotes: 0

Haresh Ghatala
Haresh Ghatala

Reputation: 2006

I have "fixed" the problem, by setting view controllers to UIPageViewController in viewWillAppear: again, because when this method is called, spine location for page view controller is correct and based on this information i set one, or two pages (view controllers)

- (void)viewWillAppear:(BOOL)animated
{   
    [super viewWillAppear:animated];

    if(self.pageViewController.spineLocation == UIPageViewControllerSpineLocationMid)
    {
        BookPageViewController *currentViewController = self.pageViewController.viewControllers[0];
        NSArray *viewControllers = nil;

        NSUInteger indexOfCurrentViewController = [self.modelController indexOfViewController:currentViewController];
        if (indexOfCurrentViewController == 0 || indexOfCurrentViewController % 2 == 0) {
            UIViewController *nextViewController = [self.modelController pageViewController:self.pageViewController viewControllerAfterViewController:currentViewController];
            viewControllers = @[currentViewController, nextViewController];
        } else {
            UIViewController *previousViewController = [self.modelController pageViewController:self.pageViewController viewControllerBeforeViewController:currentViewController];
            viewControllers = @[previousViewController, currentViewController];
        }
        [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward | UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];
    }

    if(self.pageViewController.spineLocation == UIPageViewControllerSpineLocationMin)
    {
        [self.pageViewController setViewControllers:[NSArray arrayWithObject:[self.pageViewController.viewControllers objectAtIndex:0]] direction:UIPageViewControllerNavigationDirectionForward | UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];
    }
}

and set UIPageViewController Delegate method as below

- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation
{
    BookPageViewController *currentViewController = self.pageViewController.viewControllers[0];

    if(UIInterfaceOrientationIsPortrait(orientation))
    {
        [self.pageViewController setViewControllers:[NSArray arrayWithObject:currentViewController] direction:UIPageViewControllerNavigationDirectionForward | UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];

        pageViewController.doubleSided = NO;

        return UIPageViewControllerSpineLocationMin;
    }

    if(UIInterfaceOrientationIsLandscape(orientation))
    {
        NSArray *viewControllers = nil;

        NSUInteger indexOfCurrentViewController = [self.modelController indexOfViewController:currentViewController];
        if (indexOfCurrentViewController == 0 || indexOfCurrentViewController % 2 == 0) {
            UIViewController *nextViewController = [self.modelController pageViewController:self.pageViewController viewControllerAfterViewController:currentViewController];
            viewControllers = @[currentViewController, nextViewController];
        } else {
            UIViewController *previousViewController = [self.modelController pageViewController:self.pageViewController viewControllerBeforeViewController:currentViewController];
            viewControllers = @[previousViewController, currentViewController];
        }
        [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward | UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];

        return UIPageViewControllerSpineLocationMid;
    }

    return UIPageViewControllerSpineLocationMin;
}

Upvotes: 0

Michael He
Michael He

Reputation: 41

Actually There is another solution for it.

The rotation just calling the willAnimateRotationToInterfaceOrientation method to the rootViewController, you have to implement the method of it.

@interface UIPageViewController (Rotation)
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration;
@end

//Implementation file

#import "UIPageViewController+Rotation.h"

@implementation UIPageViewController(Rotation)
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {}
@end

Upvotes: 4

iMathieuB
iMathieuB

Reputation: 1168

In the documentation about "supportedInterfaceOrientations" it is written:

When the user changes the device orientation, the system calls this method on the root view controller or the topmost presented view controller that fills the window

Did you try setting the rootViewController for the main windows to your current NavigationController classes?

Like in the AppDelegate:

self.window.rootViewController = nvc;

And when your navigationController is changing, set the rootViewController again...

Upvotes: 2

Related Questions