You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

iOS 26下如何在UITabBar中显示5个以上的标签页

iOS 16下如何在UITabBar中显示5个以上的标签页

嘿,这个问题我之前帮好几个开发者踩过坑,苹果确实把原生UITabBar的可见标签数默认锁死在5个,超过的都会被塞进那个默认的「更多」页面里。不过有几个靠谱的办法能解决这个需求,我给你详细拆解一下:

方法一:调整原生UITabBar的布局(快速但有小风险)

这种方法不用完全重写组件,直接修改原生TabBar的item宽度和布局规则就能显示更多标签。不过要注意:虽然目前iOS 16下可行,但苹果后续版本可能会限制这类调整,而且审核时存在极小概率被标记的可能(只要不碰私有API,一般没问题)。

具体代码可以这么写,在你的UITabBarControllerviewDidLoad或者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的样式,比如添加图标、调整字体
    }
}

不过这种方法还是会有「更多」跳转页面,适合只是想优化体验,而不是直接显示所有标签的场景。

最后给你几个小提醒

  1. 不管用哪种方法,都要确保标签的可点击区域足够大(苹果建议最小44x44pt),避免用户点击困难;
  2. 如果标签数特别多,建议在自定义TabBar中支持横向滚动(把StackView放在UIScrollView里),避免标签挤得看不清;
  3. 适配不同设备时,记得测试小屏机型(比如iPhone SE),必要时可以隐藏标签文字,只显示图标。

如果还有具体的细节问题,比如样式调整、横竖屏适配,随时问我就行! 😊

火山引擎 最新活动