Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rotation of UIPageViewController in Container View Controller

I have a UIViewController that contains other ViewControllers. Initial ViewController is set in viewDidLoad:

FirstViewController *first = [FirstViewController alloc] init];
first.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
first.view.frame = m_content.frame;

[self addChildViewController:first];
[m_content.view addSubview:first.view];
[first didMoveToParentViewController:self];
m_activeViewController = first;

This Container Controller has implemented automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers to return YES. It has also implemented to manualy forward rotation changes to non active ViewControllers

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return YES;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    for(UIViewController *vc in m_viewControllers)
    {
        if(vc != [m_activeViewController]
            [vc willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    }
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    for(UIViewController *vc in m_viewControllers)
    {
        if(vc != [m_activeViewController]
            [vc didRotateFromInterfaceOrientation:fromInterfaceOrientation];
    }
}

When menu button is tapped i make the transition between ViewControllers.

- (void)onMenuItemTapped:(id)sender
{
    UIViewController *vc = [m_viewControllers objectAtIndex:sender.tag];

    vc.view.frame = m_content.frame;
    [self addChildViewController:vc];
    [self transitionFromViewController:m_activeViewController toViewController:vc duration:0 options:UIViewAnimationOptionTransitionNone animations:nil completion:^(BOOL finished) {
    [vc didMoveToParentViewController:self];
    [m_activeViewController removeFromParentViewController];
    m_activeViewController = vc;
    }];
}

This transition works fine for my "normal" ViewControllers and they are displayed properly after orientation changes, even if they are not active. However, one of these Child View Controllers, called SecondCV, has UIPageViewController as a Child View Controller. I have UIPageViewControllerDelegate and UIPageViewControllerDataSource set to this SecondCV and in pageViewController:spineLocationForInterfaceOrientation: I return UIPageViewControllerSpineLocationMin for Portrait and UIPageViewControllerSpineLocationMid for Landscape. Rotation for this SecondVC works correctly when its active - there are two pages on the landscape and one on the portrait mode displayed correctly. But when this SecondVC is not active the rotation is incorrect. Even if pageViewController:spineLocationForInterfaceOrientation: is called, there is still one page in both Portrait and Landscape mode. I am trying to fix this for some time, but i dont see any other options. Do you have any ideas how to fix this?

Thank you.

like image 720
DaNY Avatar asked Apr 13 '12 08:04

DaNY


1 Answers

I have solved this kind of tricky.

Actually the SecondVC was rotated correctly, or at least, spine location was changed correctly. So when I have rotated the device and the SecondVC was not active view controller in parent view, it HAS received rotation messages and pageViewController:spineLocationForInterfaceOrientation: was called also. I set the correct spine location for new interface orientation and called setViewControllers to SecondVC's page view controller. Problem was, that even if i set two view controller for UIPageViewControllerSpineLocationMid, after displaying SecondVC there was still just one, like in UIPageViewControllerSpineLocationMin.

I have "fixed" the problem, by setting view controllers to page view controller 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
{
if(m_pageController.spineLocation == UIPageViewControllerSpineLocationMid)
{
    LeftPageController *left;
    RightPageController *right;
    if(m_pageController.viewControllers.count > 0)
    {
        left = [m_pageController.viewControllers objectAtIndex:0];

        right = [m_storyboard instantiateViewControllerWithIdentifier:@"rightPage"];
        [right loadView];
    }

    [m_pageController setViewControllers:[NSArray arrayWithObjects:left, right, nil] direction:UIPageViewControllerNavigationDirectionForward | UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];

    [m_left hideGallery];
}

if(m_pageController.spineLocation == UIPageViewControllerSpineLocationMin)
{

    [m_pageController setViewControllers:[NSArray arrayWithObject:[m_pageController.viewControllers objectAtIndex:0]] direction:UIPageViewControllerNavigationDirectionForward | UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];
}

[super viewWillAppear:animated];
}


- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation
{
if(UIInterfaceOrientationIsPortrait(orientation))
{
    LeftPageController *left = [pageViewController.viewControllers objectAtIndex:0];
    [pageViewController setViewControllers:[NSArray arrayWithObject:left] direction:UIPageViewControllerNavigationDirectionForward | UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];

    pageViewController.doubleSided = NO;     

    return UIPageViewControllerSpineLocationMin;
}

if(UIInterfaceOrientationIsLandscape(orientation))
{    
    LeftPageController *left;
    RightPageController *right;
    if(pageViewController.viewControllers.count > 0)
    {
        left = [pageViewController.viewControllers objectAtIndex:0];
        right = [m_storyboard instantiateViewControllerWithIdentifier:@"rightPage"];
        [right loadView];
    }

    [pageViewController setViewControllers:[NSArray arrayWithObjects:left,right, nil] direction:UIPageViewControllerNavigationDirectionForward | UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];

    return UIPageViewControllerSpineLocationMid;
}

return UIPageViewControllerSpineLocationMin;
}

I know i am doing the same thing twice, but thats the price i am willing to pay in this case. Why after calling pageViewController:spineLocationForInterfaceOrientation: and setting two view controllers for Landscape, when SecondVC is inactive, is only one ViewController in m_pageController in viewWillAppear: after activating SecondVC stays a mystery for me.

like image 121
DaNY Avatar answered Sep 20 '22 23:09

DaNY