Introduction
iOS Tab Bar navigation development is one of our core competencies. When a project with tab bar navigation comes to us, we start with the system component UITabBarController. Apple recommends it for applications with two to five equal-level sections. It seems simple: drag a controller, configure tabs — done. But nuances appear immediately when you need a custom appearance, a badge with a dynamic counter, or specific behavior on a repeated tap on an active tab. As certified specialists with 7 years of experience, we have implemented tab bar navigation in dozens of projects, from news apps to banking clients. We've faced each typical mistake and now guarantee that your tab bar will pass App Store review on the first try. The cost of basic tab bar setup starts from $30 to $90.
Typical Challenges
Custom appearance setup. Since iOS 15, Apple changed the customization system — UITabBar.appearance() no longer works for some parameters. The correct approach now is UITabBarAppearance + UITabBarItemAppearance. If you don't account for this, on iOS 15+ the tab bar gets a white or gray background instead of custom, making the app look broken:
let appearance = UITabBarAppearance() appearance.configureWithOpaqueBackground() appearance.backgroundColor = .systemBackground tabBar.standardAppearance = appearance tabBar.scrollEdgeAppearance = appearance This snippet sets a uniform background for both states. We always include it in our project template — it saves 20–30 minutes of debugging on a new SDK.
Badge counters. tabBarItem.badgeValue = "3" works out of the box, but the red circle cannot be color-changed without additional effort. Since iOS 10, there’s a badgeColor property, but it’s often overlooked. If you need a completely non-standard shape — like a square badge with rounded corners — you have to create a custom overlay on top of the tab icon. Comparison of approaches:
| Method | Complexity | Flexibility |
|---|---|---|
badgeColor |
Low | Only color |
setBadgeTextAttributes |
Medium | Text and shadow |
| Custom UIView | High | Full customization |
For 90% of scenarios, badgeColor is enough. We use a custom view only when we need to animate the badge (e.g., pulsation) — that happens once every five projects.
When do you need a custom badge widget?
If you need an animated badge (pulsation, color change on event) or a non-standard shape (triangle, rounded square), standard tools won't work. We developed a reusable component that is added as a subview to the tabBarButton and syncs with badgeValue.Repeated tap on an active tab. By default, nothing happens. The user expects the list to scroll to the top. Implementation via UITabBarControllerDelegate:
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { guard let nav = viewController as? UINavigationController, let top = nav.topViewController, let scroll = top.view.subviews.first(where: { $0 is UIScrollView }) as? UIScrollView else { return } scroll.setContentOffset(.zero, animated: true) } This code is a universal solution. We've added it to our component library and use it in every project. It saves 30 minutes on integration. The ready-made solution works 5 times faster than writing your own from scratch.
Hiding the tab bar on scroll is another common request. It's implemented by observing the contentOffset of a UIScrollView. We hide the tab bar with animation synchronized with the content to avoid jerking. This pattern is described in Apple's HIG documentation.
How to Set Up Custom Tab Bar Appearance on iOS 15+?
On iOS 15–17, direct setting of tintColor and barTintColor stopped working. Instead, use UITabBarAppearance. Follow three steps:
- Create a
UITabBarAppearance. - Set
backgroundColororbackgroundEffect. - Assign to
standardAppearanceandscrollEdgeAppearance.
Comparison with iOS 14: On iOS 14, you could get away with a single line tabBar.barTintColor = ..., now it's 3 times more code, but the flexibility is higher — you can set different styles for normal state and when scrolling. We always configure both to avoid a white background on iOS 15+.
Why Doesn't a Repeated Tap on a Tab Scroll to the Top?
This is a known issue: UITabBarController does not trigger scroll-to-top by default. The reason is that Apple left this logic to the developer. We solve it via the delegate as shown above. Moreover, if a tab contains multiple scroll views (e.g., Carousel + list), you need to determine which one to scroll. We use first(where:) — for standard hierarchies this is sufficient.
SwiftUI
In SwiftUI, we use TabView with the .tabItem modifier. With iOS 18, a new Tab type and sidebar support for iPad appeared. However, for complex custom animations or badges with dynamic updates, TabView still falls short. In such cases, we wrap UITabBarController via UIViewControllerRepresentable. This gives full control without performance loss — only 40–50 lines of code.
What's Included in the Work
- Setting up
UITabBarControllerorTabViewwith the required number of tabs. - Custom appearance using
UITabBarAppearanceconsidering iOS 15+. - Badge counters updating from notification service (APNs/FCM).
- Scroll to top on repeated tab tap.
- Hiding the tab bar on scroll (optional).
- Deep linking configuration for each tab.
- iPad adaptation: tab bar can be replaced with split view.
Time Estimates
| Task | Time |
|---|---|
| Basic tab bar setup | 1 day |
| Custom design | 0.5 day |
| Badge and notifications | 0.5–1 day |
| Scroll-to-top and hiding | 0.5 day |
| iPad adaptation | 1–2 days |
Order iOS Tab Bar navigation development with our help. Get a consultation and accurate project estimate — just contact us with a description of the functionality. Reduce development time by 30% using ready-made components.







