UITabBarController Not Displaying Tab Bar Items - iOS 18+
Asked Answered
E

2

9

After upgrading my project to iOS 18, I’ve encountered an issue where the UITabBarController no longer displays the tab bar items or icons properly. The same code has been working flawlessly across iOS versions 11 to 17, so the problem seems specific to iOS 18. Additionally, I've noticed that the selectedIndex occasionally gets set to Int.max, which leads to out-of-bounds values and results in the wrong tab being selected.

Expected Behavior:

  • Tab bar items/icons should display correctly, as they did in iOS 11–17.
  • The first tab should be selected by default.
  • selectedIndexshould not be set to Int.max.

Actual Behavior:

  • Tab bar items/icons are not displaying correctly.
  • The first tab is not selected by default
  • selectedIndex gets set to Int.max, causing defaulting to the wrong tab.

General Notes:

  • Xcode Version 16.1 beta (16B5001e)
  • iOS 18.1
  • I contacted Apple Support and they marked the issue as resolved with no explanation.

Are there any changes to the UITabBarController or tab bar layout behavior in iOS 18 that I need to be aware of? How can I fix or work around this issue to ensure my UITabBarController behaves as it did in previous iOS versions?

Here is the code snippet:

import UIKit

class MainTabBarController: UITabBarController {
    enum ViewControllerIndex: Int, CaseIterable {
        case channels

        var name: String {
            switch self {
            case .activity: return "Activity"
            }
        }
    }
    private var tabBarViewControllers: [UIViewController] = []
    var tabItems: [MainTabBarController.ViewControllerIndex] = ViewControllerIndex.allCases

    override func viewDidLoad() {
        super.viewDidLoad()

        let tabBarItems = self.tabBar.items ?? []
        for anItem in tabBarItems {
            anItem.setTitleTextAttributes(
                [NSAttributedString.Key.foregroundColor: UIColor.clear],
                for: .normal
            )
        }
        tabBarViewControllers = viewControllers ?? []
        updateVisibleViewControllers(animated: false)
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        // Manually laying out tab bar sub views to fix a rendering problem when multitasking view size changes
        tabBar.layoutSubviews()
    }

    func updateVisibleViewControllers(animated: Bool) {
        var tabItems: [MainTabBarController.ViewControllerIndex] = []
        tabItems.append(contentsOf: [.channels]) // other tabs here
        var subset: [UIViewController] = []
        for item in tabItems {
            subset.append(tabBarViewControllers[item.rawValue])
        }
        var updatedSelectedIndex = selectedIndex
        if self.tabItems.count > selectedIndex {
            let selectedSection = self.tabItems[selectedIndex]
            updatedSelectedIndex = tabItems.firstIndex(of: selectedSection) ?? 0
        }
        setViewControllers(subset, animated: false)
        self.tabItems = tabItems

        if selectedIndex != updatedSelectedIndex {
            self.selectedIndex = updatedSelectedIndex
        }
    }

    func select(_ section: MainTabBarController.ViewControllerIndex) {
        if let index = self.tabItems.firstIndex(of: section) {
            self.selectedIndex = index
        }
    }

    private func indexOfBarItem(_ barItem: UITabBarItem) -> Int {
        let items = tabBar.items ?? []
        return items.firstIndex(of: barItem) ?? 0
    }

}

iOS 17.5 vs iOS 18.1

Evidence answered 10/9, 2024 at 16:29 Comment(1)
we have missing tab titles on 18+, looks like an Apple bug, and this "they marked the issue as resolved with no explanation" sounds not so encouraging ;/Sabaean
B
0
[self.tabBar setTranslucent: NO];

Set to YES or mark this code. work for me

Bowfin answered 26/9, 2024 at 10:17 Comment(0)
T
0

Even though it doesn't look like it answers your question because I don't see you setting the title and image in your code, the reason we had an empty tab bar was because we were altering titles and images in code from an existing tab bar item created in the IB. This doesn't seem to work anymore. Our fix for iOS 18, including the ugly new tab bar at the top of the screen is the following in the viewDidLoad method.

Swift:

if #available(iOS 18.0, *) {
    for child in viewControllers {
        child.tabBarItem = UITabBarItem(title: child.tabBarItem.title, image: child.tabBarItem.image, selectedImage: child.tabBarItem.selectedImage)
    }

    if UIDevice.current.userInterfaceIdiom == .pad {
        traitOverrides().horizontalSizeClass = UIUserInterfaceSizeClass.compact
    }
}

Objective-C:

if (@available(iOS 18.0, *)) {
    for (UIViewController *child in [self viewControllers]) {
        [child setTabBarItem:[[UITabBarItem alloc] initWithTitle:[[child tabBarItem] title] image:[[child tabBarItem] image] selectedImage:[[child tabBarItem] selectedImage]]];
    }
    
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) [[self traitOverrides] setHorizontalSizeClass:UIUserInterfaceSizeClassCompact];
}
Tremor answered 30/9, 2024 at 14:14 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.