Search code examples
iosobjective-cuikituisplitviewcontroller

Animate visibility of master detail controller of UISplitViewController


In my UISplitViewController, I want the master view controller to only be allowed to display when in Portrait orientation or when my detail view controller is not displaying a type of controller, MyFullScreenViewController. I've implemented the UISplitViewControllerDelegate to indicate this appropriately.

-(BOOL)splitViewController:(UISplitViewController *)svc
  shouldHideViewController:(UIViewController *)vc
             inOrientation:(UIInterfaceOrientation)orientation
{
    if (UIInterfaceOrientationIsPortrait(orientation) ||
        [[self.navigationController topViewController] isKindOfClass:[MyFullScreenViewController class]])
    {
        return YES;
    }
    return NO;
}

However, the UISplitViewController only invokes the delegate during rotation. So MyFullScreenViewController implements a viewWillAppear:animated and viewWillDisappear:animated.

- (void)viewWillAppear:(BOOL)animated
{
    [self fakeRotationOfSplitViewController];
    [super viewWillAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
    [self fakeRotationOfSplitViewController];
    [super viewWillDisappear:animated];
}
-(void)fakeRotationOfSplitViewController
{
    UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];
    CGFloat duration = 1.0f;
    CGFloat fakeDuration = 0.0f;

    [UIView animateWithDuration:duration
                          delay:0.0f
                        options:UIViewAnimationOptionCurveEaseInOut
                     animations:^{
                         [[self splitViewController] willAnimateRotationToInterfaceOrientation:orientation
                                                                                      duration:fakeDuration];
                         [[self splitViewController] willRotateToInterfaceOrientation:orientation
                                                                             duration:fakeDuration];
                         [[self splitViewController] didRotateFromInterfaceOrientation:orientation];
                     } completion:^(BOOL finished) {

                     }];

}

Everything works except the animation. The master view controller immediately disappears and reappears prior to the UINavigationController object's push and prior to the pop animation.

The documentation is unclear whether willRotateToInterfaceOrientation:duration: and didRotateFromInterfaceOrientation: should be called within the animation block, but I suspect they shouldn't to allow the view controller to animate it changes in response to the message. However if they fall outside the animation block, the master view controller will sometimes disappear.


Solution

  • The animation was not working because I never called viewWillLayoutSubviews after didRotateFromInterfaceOrientation:.

    [UIView animateWithDuration:duration
                              delay:0.0f
                            options:UIViewAnimationOptionCurveEaseInOut
                         animations:^{
                             [[self splitViewController] willAnimateRotationToInterfaceOrientation:orientation
                                                                                          duration:fakeDuration];
                             [[self splitViewController] willRotateToInterfaceOrientation:orientation
                                                                                 duration:fakeDuration];
                             [[self splitViewController] didRotateFromInterfaceOrientation:orientation];
                             [[self splitViewController] viewWillLayoutSubviews];
                             [[[self splitViewController] view] layoutSubviews];
                         } completion:^(BOOL finished) {
    
                         }];