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
相关产品推荐
相关产品推荐

