iOS

⌘K
  1. Home
  2. Docs
  3. iOS
  4. UI Container Controllers
  5. UINavigationController

UINavigationController

What is UINavigationController?

UINavigationController is a container view controller that manages a stack of view controllers to provide hierarchical navigation in an iOS app. It allows users to navigate between screens using a navigation bar with a back button.


1. Key Features of UINavigationController

Manages a Stack of View Controllers – Enables hierarchical navigation.
Provides a Navigation Bar – Displays titles, buttons, and actions.
Supports Push and Pop Transitions – Moves forward and backward between screens.
Customizable Appearance – Change bar colors, text, and animations.
Integration with Tab Bar Controller – Works well with UITabBarController.


2. Creating a UINavigationController

You can create a UINavigationController in two ways:

  • Using Storyboard
  • Programmatically

2.1 Using Storyboard

  1. Drag a UINavigationController from the Object Library into your storyboard.
  2. Set its root view controller (e.g., MainViewController).
  3. Add additional view controllers for navigation.
  4. Use pushViewController(_:animated:) to navigate forward.
  5. Use popViewController(animated:) to go back.

2.2 Creating UINavigationController Programmatically

import UIKit

class MainViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        title = "Home"
        
        let button = UIButton(type: .system)
        button.setTitle("Go to Details", for: .normal)
        button.frame = CGRect(x: 100, y: 200, width: 200, height: 50)
        button.addTarget(self, action: #selector(goToDetails), for: .touchUpInside)
        view.addSubview(button)
    }

    @objc func goToDetails() {
        let detailVC = DetailViewController()
        navigationController?.pushViewController(detailVC, animated: true)
    }
}

class DetailViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .lightGray
        title = "Details"
    }
}

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(
        _ scene: UIScene,
        willConnectTo session: UISceneSession,
        options connectionOptions: UIScene.ConnectionOptions) {
        
        guard let windowScene = (scene as? UIWindowScene) else { return }
        window = UIWindow(windowScene: windowScene)
        
        let navController = UINavigationController(rootViewController: MainViewController())
        window?.rootViewController = navController
        window?.makeKeyAndVisible()
    }
}

This creates a basic UINavigationController with two screens.


3. Navigating Between View Controllers

3.1 Push a New View Controller

To navigate to a new screen:

let detailVC = DetailViewController()
navigationController?.pushViewController(detailVC, animated: true)

3.2 Pop Back to Previous View Controller

To go back to the previous screen:

navigationController?.popViewController(animated: true)

3.3 Pop to the Root View Controller

To return to the first screen:

navigationController?.popToRootViewController(animated: true)

This is useful for resetting navigation to the home screen.


4. Customizing UINavigationBar

4.1 Changing the Navigation Bar Color

navigationController?.navigationBar.barTintColor = UIColor.systemBlue

4.2 Changing the Title Font & Color

let attributes = [NSAttributedString.Key.foregroundColor: UIColor.white,
                  NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 18)]
navigationController?.navigationBar.titleTextAttributes = attributes

4.3 Hiding the Navigation Bar

navigationController?.setNavigationBarHidden(true, animated: true)

Useful for fullscreen pages like login or onboarding screens.


5. Adding Custom Buttons to Navigation Bar

5.1 Adding a Right Bar Button

navigationItem.rightBarButtonItem = UIBarButtonItem(
    title: "Edit", 
    style: .plain, 
    target: self, 
    action: #selector(editTapped)
)

@objc func editTapped() {
    print("Edit button tapped!")
}

This adds a button on the top right corner of the navigation bar.


6. Implementing a Back Button with Custom Action

By default, UINavigationController provides a back button, but you can customize it:

navigationItem.leftBarButtonItem = UIBarButtonItem(
    title: "Back", 
    style: .plain, 
    target: self, 
    action: #selector(backTapped)
)

@objc func backTapped() {
    navigationController?.popViewController(animated: true)
}

This allows custom handling when the back button is pressed.


7. Swipe to Go Back Gesture

The navigation controller includes a built-in swipe-to-go-back feature. You can enable or disable it:

navigationController?.interactivePopGestureRecognizer?.isEnabled = false

Useful if you want to prevent accidental swiping in certain screens.


8. UINavigationController with UITabBarController

UINavigationController can be used inside a UITabBarController.

let homeVC = UINavigationController(rootViewController: HomeViewController())
let profileVC = UINavigationController(rootViewController: ProfileViewController())

let tabBarController = UITabBarController()
tabBarController.viewControllers = [homeVC, profileVC]

Each tab now has its own navigation stack.


9. Example: Full UINavigationController Implementation

import UIKit

class HomeViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        title = "Home"

        let button = UIButton(type: .system)
        button.setTitle("Go to Profile", for: .normal)
        button.frame = CGRect(x: 100, y: 200, width: 200, height: 50)
        button.addTarget(self, action: #selector(goToProfile), for: .touchUpInside)
        view.addSubview(button)
    }

    @objc func goToProfile() {
        let profileVC = ProfileViewController()
        navigationController?.pushViewController(profileVC, animated: true)
    }
}

class ProfileViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .lightGray
        title = "Profile"

        navigationItem.rightBarButtonItem = UIBarButtonItem(
            title: "Settings", 
            style: .plain, 
            target: self, 
            action: #selector(goToSettings)
        )
    }

    @objc func goToSettings() {
        let settingsVC = SettingsViewController()
        navigationController?.pushViewController(settingsVC, animated: true)
    }
}

class SettingsViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        title = "Settings"
    }
}

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }
        window = UIWindow(windowScene: windowScene)

        let navController = UINavigationController(rootViewController: HomeViewController())
        window?.rootViewController = navController
        window?.makeKeyAndVisible()
    }
}

This creates a UINavigationController with Home → Profile → Settings screens.


10. Summary

✔️ UINavigationController manages hierarchical navigation with push and pop transitions.
✔️ Supports custom navigation bar styles, buttons, and gestures.
✔️ Works well with UITabBarController for tab-based apps.
✔️ Provides back navigation and swipe gestures.

Would you like help with custom transitions or animations in UINavigationController? 🚀