Thursday, October 9, 2014

How to Hide the Navigation Bar on an iOS View


Introduction

Many iOS apps use a navigation controller as the main way to link different views together. 
By default the navigation controller inserts a navigation bar at the top of each view. This is usually desirable as it provides a visual indication of the structure of your app. However there are some circumstances where it is desirable to hide the navigation bar for some views within your app. For example if a view's purpose is to display a picture or some other graphic you may want to use the whole of the display.

In this article I am going to discuss how to do this using iOS8 and Swift.


When to Hide the Navigation Bar

If you want the navigation bar to appear on some views but not others it usually make most sense to make the change when the app transitions from one view to another. The base UIViewController class has some methods that are called when this happens and you can override those methods in your UIViewController subclass.

The methods are:

viewWillAppear
viewDidAppear
viewWillDisappear
viewDidDisappear

The viewWillAppear method is called just before the view is shown and the viewDidAppear method is called just after the transition from the old view to the new one completes.

The navigation bar can be hidden or shown with an animation. The animation shows the bar sliding up to the top of the screen when hidden and down to its original place when shown. If you want the user to see the animation you should hide it in the viewDidAppear method. 

Similarly the viewWillDisappear and viewDidDisappear methods are called either side of the view being hidden. The user will only see the animation if you put the code to show the navigation bar in the viewDidDisappear method. Even then the animation will actually be seen on the new view. 

In Swift the overrides will look like this:


    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
    }

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
    }
    
    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
    } 

    override func viewDidDisappear(animated: Bool) {
        super.viewDidDisappear(animated)
    } 

Calling the superclass versions of these methods is not necessary if you subclass the UIViewController class directly. However if you have created any intermediary classes you may want to call them.


How to Show or Hide the Navigation Bar

Whether the navigation bar is shown or not is controlled by both a property and a method of the UINavigationController class. The property is called navigationBarHidden and the method is called setNavigationBarHidden.The difference between the two is that the method includes a parameter to set whether the transition is animated.

Before you can use either of these you need to get a reference to your View's navigation controller. The UIViewController base class has a property that will hold a reference to its navigation controller if it has one. If the view controller does not have a navigation controller assigned to it the value of this property will be nil. In Swift this property is implemented as an optional value. 

You could just set these values using one line of code:

navigationController?.setNavigationBarHidden(true, animated: true)

or:

navigationController?.navigationBarHidden = true

Because navigationController is an optional value these lines will just fail silently if the navigationController property is nil. The problem with this is that there is no way of knowing if it failed because the navigationController was nil or because the method call or property assignment failed.

Swift has a convention that tests for nil before attempting to use the object.

        if let navController = navigationController {
            navController.setNavigationBarHidden(true, animated: true)
        }


The 'if let' line assigns the optional value to a constant. If the value is nil the 'if' considers the assignment a false value and so the body of the if statement is not executed. If you want to known that the assignment failed you can just add an else clause.


        if let navController = navigationController {
            navController.setNavigationBarHidden(true, animated: true)
        } else {
            println("Navigation Controller Missing.")
        }

Conclusion

 The final code looks like this if you want the transition of the navigation bar animated:


    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        if let navController = navigationController {
            navController.setNavigationBarHidden(true, animated: true)
        } else {
            println("Navigation Controller Missing.")
        }
    }
    
    override func viewDidDisappear(animated: Bool) {
        super.viewDidDisappear(animated)
        if let navController = navigationController {
            navController.setNavigationBarHidden(false, animated: true)
        } else {
            println("Navigation Controller Missing.")
        }
    }

Or like this if you do not want the transition of the navigation bar animated:


    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        if let navController = navigationController {
            navController.navigationBarHidden = true
        } else {
            println("Navigation Controller Missing.")
        } 
    }
    
    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        if let navController = navigationController {
            navController.navigationBarHidden = false
        } else {
            println("Navigation Controller Missing.")
        }
    }


No comments:

Post a Comment