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:
import UIKit
let tabBarController = UITabBarController()
let firstVC = UIViewController()
let secondVC = UIViewController()
tabBarController.viewControllers = [firstVC, secondVC]
window?.rootViewController = tabBarControllerKey Properties of UITabBarController
Below are the most commonly used properties of UITabBarController:
| Property | Type | Description |
|---|---|---|
viewControllers | [UIViewController]? | The array of view controllers managed by the tab bar controller. |
selectedViewController | UIViewController? | The currently selected view controller. |
selectedIndex | Int | The index of the currently selected tab. |
tabBar | UITabBar | The tab bar displayed at the bottom. |
delegate | UITabBarControllerDelegate? | Delegate for handling tab selection and other events. |
customizableViewControllers | [UIViewController]? | View controllers that can be rearranged by the user (if enabled). |
moreNavigationController | UINavigationController | The navigation controller for the "More" tab (appears when there are more than five tabs). |
Example: Configuring Properties:
tabBarController.selectedIndex = 0
tabBarController.tabBar.tintColor = .systemBlue
tabBarController.tabBar.backgroundColor = .systemGray6Key Methods of UITabBarController
UITabBarController provides methods to manage its view controllers:
| Method | Description |
|---|---|
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:
tabBarController.setViewControllers([firstVC, secondVC], animated: true)UITabBarControllerDelegate Methods
The UITabBarControllerDelegate protocol provides methods to handle tab-related events:
| Method | Description |
|---|---|
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:
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:
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:
firstVC.tabBarItem.badgeValue = "3"Customizing Tab Bar Appearance
Customize the tab bar’s appearance using UITabBar properties.
Example:
tabBarController.tabBar.tintColor = .systemBlue // Selected tab color
tabBarController.tabBar.unselectedItemTintColor = .systemGray // Unselected tab color
tabBarController.tabBar.backgroundColor = .systemBackgroundHandling 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:
tabBarController.customizableViewControllers = tabBarController.viewControllersCombining with UINavigationController
Each tab often contains a UINavigationController for hierarchical navigation within the tab.
Example:
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
accessibilityLabelandaccessibilityTraitsfor tab bar items.swiftfirstVC.tabBarItem.accessibilityLabel = "Home tab" firstVC.tabBarItem.accessibilityTraits = .buttonUse 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
viewControllersis set and each view controller has a validtabBarItem. - Icons or Titles Missing: Verify
tabBarItemproperties (title, image) are correctly set. - More Tab Issues: Check
customizableViewControllersfor user customization or inspectmoreNavigationController. - Appearance Issues: Test
UITabBarproperties liketintColoracross light/dark modes. - Navigation Issues: Ensure navigation controllers are correctly nested for hierarchical navigation.
Example: Complete UITabBarController Setup
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
}
}