How do I “legally” fade out the navigation bar in an app?

北战南征 提交于 2019-11-30 06:53:14

This was a fun one to solve.

It should have been very straight-forward: use UIView transitionWithView to perform a cross-fade between the hidden and non-hidden states of the navigation bar, as set by the public API setNavigationBarHidden:animated:. In fact this works for "fading out" the navbar, but fading it back in had an issue. The issue was that the navbar would slide into place regardless of the fact that UIView +transitionWithView: doesn't animate animatable properties (e.g. frame) unless you specify UIViewAnimationOptionAllowAnimatedContent.

To me this says that internally the UINavigationController repositions the UINavigationBar inside an animation block regardless of whether animating was specified in the call to setNavigationBarHidden:animated:. The duration for this animation block is probably set to '0' when animate: is set to NO.

The solution is to set the navigation bar visible (sans animation) before the cross-fade transition. This ensures that the navigation bar begins the cross-fade in the correct position, and that the cross-fade will only reveal the new non-hidden state.

My sample project is a standard Single View Application. On the storyboard is a UINavigationController, which is the entry point. I set the bar style for this controller's UINavigationBar to black-translucent (similar to the Photos app). The navigation controller's rootViewController is a simple UIViewController with a UIImageView filling the entire bounds (also like the Photos app). I added a UITapGestureRecognizer on the view to invoke the following code, in the view controller:

- (IBAction) onShowHideNavbar: (id) sender
{
    BOOL hide = !self.navigationController.navigationBarHidden;

    if ( !hide)
    {
        [self.navigationController setNavigationBarHidden: hide animated: NO];
    }

    [UIView transitionWithView: self.navigationController.view
                      duration: 1
                       options: UIViewAnimationOptionTransitionCrossDissolve
                    animations: ^{

                        [self.navigationController setNavigationBarHidden: hide animated: NO];
                    }
                    completion: nil ];
}

All this said, I don't think you'd get into any trouble (Apple Rejection) for messing with the hidden or alpha properties of the UINavigationBar directly. The docs warn against touching these because they're managed by the UINavigationController and changing them might have unseen consequences. But In My Opinion they're public APIs and as such using them shouldn't be cause for rejection.

You can't animate properties of the navigation bar of a UINavigationController legally.
However, you can show a navigation controller with hidden navigation bar (hiding it always or only on a specific view controller, as you prefer), and replace it with your "special" instance of UINavigationBar ;-)

I attach a sample project (I used an Xcode template to create it faster): FakeNavBar

Look at the viewDidLoad method of the DetailViewController:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self configureView];

    self.fakeBar = [[UINavigationBar alloc]initWithFrame:self.navigationController.navigationBar.bounds];


    UIBarButtonItem *back = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(back)];



    UINavigationItem *backItem = [[UINavigationItem alloc]initWithTitle:@"Back"];
    backItem.leftBarButtonItem = back;
    [self.fakeBar pushNavigationItem:backItem animated:YES];

    [self.view addSubview:self.fakeBar];

}

Here's a video of the final product on YouTube.

A way around this (I don't know exactly how you are planning to animate to the next view or in what way you want to incorporate the fade) is to render the current view to a uiimage, make a full screen UIImageView with this image (basically replacing your existing UIView with a picture of it) Swap in your new view behind the image view and then fade out the image view.

You can also crop out just the UInavigationBar part of the image and fade that after the transition. This way you can apply any image effects to the 'UINavgationBar' without getting rejected by apple.

I know of no Apple-sanctioned way to do this. I doubt you would be rejected for modifying the alpha value of the navigationBar, but like you, I don't know for certain.

You can of course implement your own navigation controller/navigation bar with which you can do anything you want. That is what I have done in my applications when I need to do something like this. Apple has been totally fine with that. Bonus points: Apple can change their controls as much as they want without breaking your layout if you use custom controls. This was recently a problem in certain areas of our application where the app looks VASTLY different in different versions of iOS (7).

Anyway, that's my 2 cents...

If you keep reading, this is the next paragraph right after your quote:

In iOS v5.0 and later, you can customize the appearance of the bar using the methods listed in “Customizing the Bar Appearance.” You can customize the appearance of all navigation bars using the appearance proxy ([UINavigationBar appearance]), or just of a single bar.

Clicking the link (Customizing the Bar Appearance) will show you this:

Customizing the Bar Appearance
tintColor property
– backgroundImageForBarMetrics:
– setBackgroundImage:forBarMetrics:
– titleVerticalPositionAdjustmentForBarMetrics:
– setTitleVerticalPositionAdjustment:forBarMetrics:
titleTextAttributes property

So in iOS v5.0 and later, that is the list that you can (legally) change. You might be able to play some games with the alpha of the tintColor or a background image in order to make it look like it is fading out (and then hide it) but I doubt that it will look quite right. Probably worth an attempt though.

You may not be able to easily fade the navigation bar, but you can easily fade a picture of the navigation bar. So one thing you could do is to create an image of the nav bar, replace the nav bar with your image, and then animate the image view with alpha going to 0. Or you could do the opposite: position an image view on top of the nav bar, and fade in an image of whatever is supposed to be behind the nav bar.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!