Skip to content

UITabBarController

UITabBarController is a UIKit class that manages a tab-based interface, allowing users to switch between multiple view controllers using a tab bar at the bottom of the screen. It is a subclass of UIViewController and is commonly used for apps with distinct, parallel sections, such as Settings or Music. This document covers the key properties, methods, and usage of UITabBarController, along with examples and best practices.

Overview of UITabBarController

UITabBarController organizes content by presenting multiple view controllers, each associated with a tab in the tab bar. Each tab displays an icon and optional title, and selecting a tab shows its corresponding view controller. The tab bar controller manages the navigation within each tab, often in conjunction with UINavigationController for hierarchical navigation.

Creating a UITabBarController

You can create a UITabBarController programmatically or via Interface Builder (storyboards/xibs). It requires at least one view controller to initialize.

Programmatic Example:

swift
import UIKit

let tabBarController = UITabBarController()
let firstVC = UIViewController()
let secondVC = UIViewController()
tabBarController.viewControllers = [firstVC, secondVC]
window?.rootViewController = tabBarController

Key Properties of UITabBarController

Below are the most commonly used properties of UITabBarController:

PropertyTypeDescription
viewControllers[UIViewController]?The array of view controllers managed by the tab bar controller.
selectedViewControllerUIViewController?The currently selected view controller.
selectedIndexIntThe index of the currently selected tab.
tabBarUITabBarThe tab bar displayed at the bottom.
delegateUITabBarControllerDelegate?Delegate for handling tab selection and other events.
customizableViewControllers[UIViewController]?View controllers that can be rearranged by the user (if enabled).
moreNavigationControllerUINavigationControllerThe navigation controller for the "More" tab (appears when there are more than five tabs).

Example: Configuring Properties:

swift
tabBarController.selectedIndex = 0
tabBarController.tabBar.tintColor = .systemBlue
tabBarController.tabBar.backgroundColor = .systemGray6

Key Methods of UITabBarController

UITabBarController provides methods to manage its view controllers:

MethodDescription
setViewControllers(_:animated:)Sets the array of view controllers, optionally animating the transition.
tabBarController(_:shouldSelect:)Delegate method to control whether a tab can be selected.

Example: Setting View Controllers:

swift
tabBarController.setViewControllers([firstVC, secondVC], animated: true)

UITabBarControllerDelegate Methods

The UITabBarControllerDelegate protocol provides methods to handle tab-related events:

MethodDescription
tabBarController(_:shouldSelect:)Called to determine if a view controller should be selected.
tabBarController(_:didSelect:)Called after a view controller is selected.
tabBarController(_:willBeginCustomizing:)Called when the user begins customizing tabs.
tabBarController(_:didEndCustomizing:changed:)Called when the user finishes customizing tabs.

Example: Implementing Delegate:

swift
tabBarController.delegate = self

extension ViewController: UITabBarControllerDelegate {
    func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
        print("Selected tab: \(tabBarController.selectedIndex)")
    }
}

Configuring Tabs

Each view controller in the viewControllers array is associated with a tab, configured via its tabBarItem property (UITabBarItem).

Setting Tab Bar Items

A UITabBarItem defines the tab’s title, icon, and optional badge. You can set it for each view controller.

Example:

swift
firstVC.tabBarItem = UITabBarItem(title: "Home", image: UIImage(systemName: "house"), tag: 0)
secondVC.tabBarItem = UITabBarItem(title: "Profile", image: UIImage(systemName: "person"), tag: 1)

Using Badges

Add a badge (e.g., a notification count) to a tab using badgeValue.

Example:

swift
firstVC.tabBarItem.badgeValue = "3"

Customizing Tab Bar Appearance

Customize the tab bar’s appearance using UITabBar properties.

Example:

swift
tabBarController.tabBar.tintColor = .systemBlue // Selected tab color
tabBarController.tabBar.unselectedItemTintColor = .systemGray // Unselected tab color
tabBarController.tabBar.backgroundColor = .systemBackground

Handling More Than Five Tabs

If more than five view controllers are added, a "More" tab appears automatically, managed by moreNavigationController. Users can access additional tabs or customize the tab order.

Example: Enabling Customization:

swift
tabBarController.customizableViewControllers = tabBarController.viewControllers

Combining with UINavigationController

Each tab often contains a UINavigationController for hierarchical navigation within the tab.

Example:

swift
let homeNav = UINavigationController(rootViewController: firstVC)
let profileNav = UINavigationController(rootViewController: secondVC)
tabBarController.viewControllers = [homeNav, profileNav]

Best Practices

  • Limit Tabs: Use 2–5 tabs for optimal usability; avoid cluttering the tab bar.

  • Use Clear Icons and Titles: Choose recognizable SF Symbols and concise titles.

  • Support Accessibility: Set accessibilityLabel and accessibilityTraits for tab bar items.

    swift
    firstVC.tabBarItem.accessibilityLabel = "Home tab"
    firstVC.tabBarItem.accessibilityTraits = .button
  • Use Auto Layout: Ensure subviews in view controllers use constraints (e.g., with SnapKit).

  • Handle State Persistence: Save and restore the selected tab index if needed (e.g., using UserDefaults).

  • Test Across Devices: Verify tab bar appearance and behavior on different screen sizes and orientations.

Troubleshooting

  • Tabs Not Showing: Ensure viewControllers is set and each view controller has a valid tabBarItem.
  • Icons or Titles Missing: Verify tabBarItem properties (title, image) are correctly set.
  • More Tab Issues: Check customizableViewControllers for user customization or inspect moreNavigationController.
  • Appearance Issues: Test UITabBar properties like tintColor across light/dark modes.
  • Navigation Issues: Ensure navigation controllers are correctly nested for hierarchical navigation.

Example: Complete UITabBarController Setup

swift
import UIKit
import SnapKit

class HomeViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackgroundColor
        navigationItem.title = "Home"
        
        let label = UILabel()
        label.text = "Welcome to Home"
        label.textAlignment = .center
        view.addSubview(label)
        
        label.snp.makeConstraints { make in
            make.center.equalToSuperview()
        }
    }
}

class ProfileViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemGray6
        navigationItem.title = "Profile"
        
        let label = UILabel()
        label.text = "Profile Screen"
        label.textAlignment = .center
        view.addSubview(label)
        
        label.snp.makeConstraints { make in
            make.center.equalToSuperview()
        }
    }
}

// App setup
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        window = UIWindow(frame: UIScreen.main.bounds)
        
        // Create view controllers
        let homeVC = HomeViewController()
        homeVC.tabBarItem = UITabBarItem(title: "Home", image: UIImage(systemName: "house"), selectedImage: UIImage(systemName: "house.fill"))
        homeVC.tabBarItem.accessibilityLabel = "Home tab"
        homeVC.tabBarItem.badgeValue = "2"
        
        let profileVC = ProfileViewController()
        profileVC.tabBarItem = UITabBarItem(title: "Profile", image: UIImage(systemName: "person"), selectedImage: UIImage(systemName: "person.fill"))
        profileVC.tabBarItem.accessibilityLabel = "Profile tab"
        
        // Wrap in navigation controllers
        let homeNav = UINavigationController(rootViewController: homeVC)
        let profileNav = UINavigationController(rootViewController: profileVC)
        
        // Configure tab bar controller
        let tabBarController = UITabBarController()
        tabBarController.viewControllers = [homeNav, profileNav]
        tabBarController.selectedIndex = 0
        tabBarController.tabBar.tintColor = .systemBlue
        tabBarController.tabBar.unselectedItemTintColor = .systemGray
        tabBarController.tabBar.backgroundColor = .systemBackground
        
        // Set delegate
        tabBarController.delegate = tabBarController as? UITabBarControllerDelegate
        
        window?.rootViewController = tabBarController
        window?.makeKeyAndVisible()
        return true
    }
}

Resources

Released under the MIT License.