Search code examples
iosuiviewcontrollerios7

How can I work around hidesBottomBarWhenPushed acting weird with the iOS 6 SDK?


I ran into the same problem described in this OpenRadar issue. As stated there:

Summary: The hidesBottomBarWhenPushed property of UIViewController doesn't work as expected for apps built with iOS 6 SDK (not beta SDKs for iOS 7). The animation is weird when hiding the bottom bar (e.g. a tab bar).

Steps to Reproduce:

  1. Create a new project with the TabBar template in Xcode 4. Add a UINavigationController to the FirstViewController. Add a button on the FirstViewController and set its action to push a new view controller. (please see the sample code attached)

  2. Run the demo on an iOS 7 beta 5 device.

  3. Press the button, back from the UINavigationController, pay attention to the animated view transitions.

Expected Results: The animation works exactly the same as on an iOS 6 device.

Actual Results: The animation looks weird. The FirstViewController is sliding down from the bottom.

Sample code: http://cl.ly/QgZZ

Is there any way to fix or work around this when building with the iOS 6 SDK?


Solution

  • This issue definitely exists. I did some investigation and found out what's causing it. When pushing a view controller with UINavigationController, you view controller's view is contained in a UIViewControllerWrapperView, which a private Apple's view managed by the UINavigationController. When the transition animation is about to occur and the hidesBottomBarWhenPushed is set to YES, this UIViewControllerWrapperView is being animated with wrong position for the Y axis, so the solution is just to overwrite this behaviour and give correct values for the animation. Here's the code:

    //Declare a property
    @property (nonatomic, assign) BOOL shouldFixAnimation;
    
    ...
    
    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
    
    #ifndef __IPHONE_7_0 //If this constant is not defined then we probably build against lower SDK and we should do the fix
        if (self.hidesBottomBarWhenPushed && [[[UIDevice currentDevice] systemVersion] floatValue] >= 7 && animated && self.navigationController) {
            self.shouldFixAnimation = YES;
        }
    #endif
    
    }
    
    -(void)viewWillLayoutSubviews {
        [super viewWillLayoutSubviews];
    
    #ifndef __IPHONE_7_0
        if(self.shouldFixAnimation) {
            self.shouldFixAnimation = NO;
            CABasicAnimation *basic = (CABasicAnimation *)[self.view.superview.layer animationForKey:@"position"]; //The superview is this UIViewControllerWrapperView
    
            //Just in case for future changes from Apple
            if(!basic || ![basic isKindOfClass:[CABasicAnimation class]]) 
                return;
    
            if(![basic.fromValue isKindOfClass:[NSValue class]])
                return;
    
            CABasicAnimation *animation = [basic mutableCopy];
    
            CGPoint point = [basic.fromValue CGPointValue];
    
            point.y = self.view.superview.layer.position.y;
    
            animation.fromValue = [NSValue valueWithCGPoint:point];
    
            [self.view.superview.layer removeAnimationForKey:@"position"];
            [self.view.superview.layer addAnimation:animation forKey:@"position"];
        }
    #endif
    
    }