You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS中如何自定义含双层图片+文字布局的UITabBarItem?

实现自定义图片-文字-图片布局的UITabBarItem

要实现这种非标准的TabBarItem布局,核心思路是替换系统默认的UITabBarItem视图,用自定义的UIStackView容器承载图片、文字、图片元素,同时兼容多语言和选中状态切换。以下是具体实现方案:

步骤1:创建自定义TabBarItem内容视图

封装一个包含「左图-文字-右图」的自定义View,负责布局和样式控制:

import UIKit

class CustomTabBarItemView: UIView {
    private let leftImageView = UIImageView()
    private let titleLabel = UILabel()
    private let rightImageView = UIImageView()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupLayout()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupLayout()
    }
    
    // 初始化布局
    private func setupLayout() {
        let stackView = UIStackView(arrangedSubviews: [leftImageView, titleLabel, rightImageView])
        stackView.axis = .horizontal
        stackView.alignment = .center
        stackView.spacing = 4 // 可根据需求调整间距
        stackView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(stackView)
        
        NSLayoutConstraint.activate([
            stackView.centerXAnchor.constraint(equalTo: centerXAnchor),
            stackView.centerYAnchor.constraint(equalTo: centerYAnchor)
        ])
        
        // 默认样式配置
        titleLabel.font = UIFont.systemFont(ofSize: 12)
        leftImageView.contentMode = .scaleAspectFit
        rightImageView.contentMode = .scaleAspectFit
        leftImageView.tintColor = .gray
        rightImageView.tintColor = .gray
        titleLabel.textColor = .gray
    }
    
    // 配置内容与选中状态
    func configure(leftImage: UIImage?, titleKey: String, rightImage: UIImage?, isSelected: Bool) {
        leftImageView.image = leftImage?.withRenderingMode(.alwaysTemplate)
        rightImageView.image = rightImage?.withRenderingMode(.alwaysTemplate)
        // 多语言适配:用NSLocalizedString读取本地化文本
        titleLabel.text = NSLocalizedString(titleKey, comment: "")
        
        // 切换选中/未选中样式
        let activeColor = UIColor.systemBlue // 可自定义选中色
        let inactiveColor = UIColor.gray
        let targetColor = isSelected ? activeColor : inactiveColor
        
        leftImageView.tintColor = targetColor
        rightImageView.tintColor = targetColor
        titleLabel.textColor = targetColor
    }
}

步骤2:自定义UITabBar替换系统视图

创建自定义UITabBar子类,负责生成所有自定义TabBarItem视图,并处理点击事件和选中状态更新:

class CustomTabBar: UITabBar {
    private var customItemViews: [CustomTabBarItemView] = []
    
    override func layoutSubviews() {
        super.layoutSubviews()
        // 首次布局时初始化自定义视图
        if customItemViews.isEmpty {
            setupCustomItems()
        }
        // 每次布局更新选中状态
        updateSelectionState()
    }
    
    // 初始化所有自定义TabBarItem
    private func setupCustomItems() {
        // 移除系统默认的UITabBarButton
        subviews.filter { $0 is UIControl }.forEach { $0.removeFromSuperview() }
        
        guard let items = items, items.count > 0 else { return }
        let itemWidth = bounds.width / CGFloat(items.count)
        let itemHeight = bounds.height
        
        for (index, item) in items.enumerated() {
            let frame = CGRect(x: CGFloat(index) * itemWidth, y: 0, width: itemWidth, height: itemHeight)
            let customView = CustomTabBarItemView(frame: frame)
            
            // 配置内容
            customView.configure(
                leftImage: item.image,
                titleKey: item.title ?? "",
                rightImage: item.selectedImage,
                isSelected: selectedItem == item
            )
            
            // 添加点击手势
            let tap = UITapGestureRecognizer(target: self, action: #selector(onItemTap(_:)))
            customView.addGestureRecognizer(tap)
            customView.tag = index
            
            addSubview(customView)
            customItemViews.append(customView)
        }
    }
    
    // 处理TabBarItem点击
    @objc private func onItemTap(_ gesture: UITapGestureRecognizer) {
        guard let index = gesture.view?.tag, let item = items?[index] else { return }
        selectedItem = item
    }
    
    // 更新所有Item的选中状态
    private func updateSelectionState() {
        guard let items = items else { return }
        customItemViews.enumerated().forEach { index, view in
            let isSelected = selectedItem == items[index]
            view.configure(
                leftImage: items[index].image,
                titleKey: items[index].title ?? "",
                rightImage: items[index].selectedImage,
                isSelected: isSelected
            )
        }
    }
}

步骤3:扩展UITabBarItem增强灵活性(可选)

如果需要给每个TabBarItem单独设置左右图片,可通过关联对象扩展UITabBarItem:

extension UITabBarItem {
    private enum AssociatedKey {
        static var leftImage: UIImage?
        static var rightImage: UIImage?
    }
    
    // 自定义左图属性
    var customLeftImage: UIImage? {
        get { objc_getAssociatedObject(self, &AssociatedKey.leftImage) as? UIImage }
        set { objc_setAssociatedObject(self, &AssociatedKey.leftImage, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
    }
    
    // 自定义右图属性
    var customRightImage: UIImage? {
        get { objc_getAssociatedObject(self, &AssociatedKey.rightImage) as? UIImage }
        set { objc_setAssociatedObject(self, &AssociatedKey.rightImage, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
    }
}

之后在setupCustomItems方法里替换为自定义属性即可:

customView.configure(
    leftImage: item.customLeftImage,
    titleKey: item.title ?? "",
    rightImage: item.customRightImage,
    isSelected: selectedItem == item
)

步骤4:在TabBarController中使用自定义UITabBar

在你的TabBarController里替换系统TabBar:

class MainTabBarController: UITabBarController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // 替换为自定义TabBar
        tabBar = CustomTabBar()
        
        // 配置子控制器的TabBarItem
        let homeVC = UIViewController()
        homeVC.tabBarItem = UITabBarItem(
            title: "tab_home", // 对应Localizable.strings中的key
            image: UIImage(systemName: "house"),
            selectedImage: UIImage(systemName: "bell")
        )
        
        let profileVC = UIViewController()
        profileVC.tabBarItem = UITabBarItem(
            title: "tab_profile",
            image: UIImage(systemName: "person"),
            selectedImage: UIImage(systemName: "gear")
        )
        
        viewControllers = [homeVC, profileVC]
    }
}

关键注意点

  • 多语言适配:通过NSLocalizedString读取本地化文本,无需为每种语言制作图片,切换语言时文字自动更新。
  • 选中状态:利用tintColor统一控制图片和文字颜色,避免重复设置。
  • 布局兼容性:自定义View使用AutoLayout,适配不同屏幕尺寸。

内容的提问来源于stack exchange,提问作者Giuseppe Ferrara

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 02:40:27