iOS 26下如何在UITabBar中显示5个以上的标签页
iOS 16下如何在UITabBar中显示5个以上的标签页
嘿,这个问题我之前帮好几个开发者踩过坑,苹果确实把原生UITabBar的可见标签数默认锁死在5个,超过的都会被塞进那个默认的「更多」页面里。不过有几个靠谱的办法能解决这个需求,我给你详细拆解一下:
方法一:调整原生UITabBar的布局(快速但有小风险)
这种方法不用完全重写组件,直接修改原生TabBar的item宽度和布局规则就能显示更多标签。不过要注意:虽然目前iOS 16下可行,但苹果后续版本可能会限制这类调整,而且审核时存在极小概率被标记的可能(只要不碰私有API,一般没问题)。
具体代码可以这么写,在你的UITabBarController的viewDidLoad或者viewWillLayoutSubviews里做调整:
override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() // 假设你要显示6个标签 let tabCount = 6 // 计算每个标签的宽度,预留少量间距避免挤在一起 let safeWidth = view.safeAreaLayoutGuide.layoutFrame.width let itemWidth = (safeWidth - CGFloat(tabCount - 1) * 1) / CGFloat(tabCount) // 强制设置每个item的宽度和间距 tabBar.itemWidth = itemWidth tabBar.itemSpacing = 1 // 设置item为填充模式,禁止系统自动调整 tabBar.itemPositioning = .fill // 如果标签文字太长,也可以强制缩小字体 UITabBarItem.appearance().setTitleTextAttributes([ NSAttributedString.Key.font: UIFont.systemFont(ofSize: 10) ], for: .normal) }
记得要在viewWillLayoutSubviews里做计算,这样横竖屏切换时能自动适配宽度。如果标签数动态变化,还要对应调整计算逻辑。
方法二:完全自定义TabBar(最稳妥,无审核顾虑)
如果想彻底摆脱系统的限制,完全自定义一个TabBar是最优解——不仅能显示任意数量的标签,还能自由定制样式(比如渐变背景、圆角、自定义徽章),而且完全符合苹果的审核规则,因为这是你自己实现的UI组件,没有修改系统私有内容。
我给你写个极简的实现示例:
1. 自定义TabBar视图
class CustomTabBar: UIView { // 点击标签的回调 var onTabSelected: ((Int) -> Void)? // 标签配置(根据你的需求修改) private let tabConfigs = [ (title: "首页", icon: "house.fill"), (title: "发现", icon: "magnifyingglass"), (title: "消息", icon: "bubble.left.fill"), (title: "我的", icon: "person.fill"), (title: "设置", icon: "gear"), (title: "收藏", icon: "bookmark.fill") ] override init(frame: CGRect) { super.init(frame: frame) setupUI() } required init?(coder: NSCoder) { super.init(coder: coder) setupUI() } private func setupUI() { backgroundColor = .systemBackground layer.borderTopWidth = 0.5 layer.borderColor = UIColor.systemGray2.cgColor // 用StackView布局所有标签按钮 let stackView = UIStackView() stackView.axis = .horizontal stackView.distribution = .fillEqually stackView.spacing = 0 stackView.translatesAutoresizingMaskIntoConstraints = false addSubview(stackView) NSLayoutConstraint.activate([ stackView.leadingAnchor.constraint(equalTo: leadingAnchor), stackView.trailingAnchor.constraint(equalTo: trailingAnchor), stackView.topAnchor.constraint(equalTo: topAnchor), stackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -safeAreaInsets.bottom) ]) // 添加每个标签按钮 for (index, config) in tabConfigs.enumerated() { let button = UIButton(type: .system) button.setTitle(config.title, for: .normal) button.setImage(UIImage(systemName: config.icon), for: .normal) // 调整图标和文字的间距 button.imageEdgeInsets = UIEdgeInsets(top: 2, left: 0, bottom: -2, right: 0) button.titleEdgeInsets = UIEdgeInsets(top: 0, left: 2, bottom: 0, right: -2) button.tag = index button.addTarget(self, action: #selector(tabTapped(_:)), for: .touchUpInside) // 默认选中第一个标签 button.tintColor = index == 0 ? .systemBlue : .systemGray stackView.addArrangedSubview(button) } } @objc private func tabTapped(_ sender: UIButton) { onTabSelected?(sender.tag) // 更新选中状态 subviews.compactMap { $0 as? UIStackView }.first?.arrangedSubviews.forEach { guard let button = $0 as? UIButton else { return } button.tintColor = button.tag == sender.tag ? .systemBlue : .systemGray } } }
2. 自定义TabBar控制器
class CustomTabBarController: UIViewController { private let customTabBar = CustomTabBar() // 存储所有要切换的视图控制器 private var viewControllers: [UIViewController] = [] override func viewDidLoad() { super.viewDidLoad() setupViewControllers() setupCustomTabBar() } private func setupViewControllers() { // 初始化你的6个视图控制器(替换成你自己的VC) viewControllers = [ UINavigationController(rootViewController: HomeVC()), UINavigationController(rootViewController: DiscoverVC()), UINavigationController(rootViewController: MessageVC()), UINavigationController(rootViewController: ProfileVC()), UINavigationController(rootViewController: SettingsVC()), UINavigationController(rootViewController: CollectionVC()) ] // 默认显示第一个VC addInitialViewController() } private func addInitialViewController() { guard let firstVC = viewControllers.first else { return } addChild(firstVC) firstVC.view.frame = view.bounds view.addSubview(firstVC.view) firstVC.didMove(toParent: self) } private func setupCustomTabBar() { customTabBar.translatesAutoresizingMaskIntoConstraints = false view.addSubview(customTabBar) // 固定在底部,适配安全区 NSLayoutConstraint.activate([ customTabBar.leadingAnchor.constraint(equalTo: view.leadingAnchor), customTabBar.trailingAnchor.constraint(equalTo: view.trailingAnchor), customTabBar.bottomAnchor.constraint(equalTo: view.bottomAnchor), customTabBar.heightAnchor.constraint(equalToConstant: 49 + view.safeAreaInsets.bottom) ]) // 处理标签切换逻辑 customTabBar.onTabSelected = { [weak self] index in guard let self = self, index < self.viewControllers.count else { return } // 移除当前显示的VC let currentVC = self.children.first currentVC?.willMove(toParent: nil) currentVC?.view.removeFromSuperview() currentVC?.removeFromParent() // 添加选中的VC let targetVC = self.viewControllers[index] self.addChild(targetVC) targetVC.view.frame = self.view.bounds self.view.insertSubview(targetVC.view, belowSubview: self.customTabBar) targetVC.didMove(toParent: self) } } }
这种实现方式完全可控,你可以根据需求调整标签的大小、样式,甚至添加动画效果。
方法三:优化默认「更多」页面的体验(折中方案)
如果不想大改代码,只是想让「更多」页面更贴合你的App风格,也可以修改系统More导航控制器的样式:
override func viewDidLoad() { super.viewDidLoad() // 修改More页面的标题 moreNavigationController.navigationBar.topItem?.title = "更多" // 隐藏More页面的导航栏 moreNavigationController.navigationBar.isHidden = true // 自定义More页面的列表样式 if let tableView = moreNavigationController.topViewController?.view as? UITableView { tableView.rowHeight = 60 tableView.separatorStyle = .none // 你还可以自定义cell的样式,比如添加图标、调整字体 } }
不过这种方法还是会有「更多」跳转页面,适合只是想优化体验,而不是直接显示所有标签的场景。
最后给你几个小提醒
- 不管用哪种方法,都要确保标签的可点击区域足够大(苹果建议最小44x44pt),避免用户点击困难;
- 如果标签数特别多,建议在自定义TabBar中支持横向滚动(把StackView放在UIScrollView里),避免标签挤得看不清;
- 适配不同设备时,记得测试小屏机型(比如iPhone SE),必要时可以隐藏标签文字,只显示图标。
如果还有具体的细节问题,比如样式调整、横竖屏适配,随时问我就行! 😊




