如何为选中的Tab Bar Item添加边框/圆圈而非仅改色?
当然可以实现!给选中的TabBarItem添加方框/圆圈样式的方法
给选中的TabBarItem设置方框或圆圈标记,而非仅依赖颜色区分,是完全可行的,下面我会分享几种不同场景下的靠谱实现方案:
方法一:自定义选中状态图标(最简单直观)
这种方法适合需求简单的场景——直接为每个TabBarItem准备带方框/圆圈的选中态图标,以及普通的未选中态图标,直接赋值给TabBarItem的对应属性即可。
步骤:
- 准备两套图标:比如
home_normal.png(普通图标)、home_selected.png(带蓝色圆圈的选中图标) - 设置TabBarItem时,指定
image和selectedImage,并设置渲染模式为alwaysOriginal(避免系统自动 tint 颜色):
// 示例:创建第一个TabBarItem let homeItem = UITabBarItem( title: "首页", image: UIImage(named: "home_normal")?.withRenderingMode(.alwaysOriginal), selectedImage: UIImage(named: "home_selected")?.withRenderingMode(.alwaysOriginal) ) // 把item赋值给对应的ViewController homeViewController.tabBarItem = homeItem
这种方法优势是实现简单,无需复杂自定义视图;缺点是样式固定,无法动态调整圆圈/方框的大小、颜色。
方法二:自定义TabBar(灵活度最高)
如果需要动态调整标记样式(比如随主题切换颜色、调整圆圈大小),可以通过继承UITabBar自定义视图逻辑,手动给选中的Item添加圆圈/方框图层。
步骤:
- 创建自定义TabBar类:
class CustomTabBar: UITabBar { // 标记图层的标识,方便后续移除旧图层 private let markerLayerName = "tabSelectionMarker" override func layoutSubviews() { super.layoutSubviews() // 先移除之前添加的标记图层,避免重复叠加 subviews.forEach { view in view.layer.sublayers?.filter { $0.name == markerLayerName }.forEach { $0.removeFromSuperlayer() } } // 获取当前选中的索引 guard let selectedIndex = tabBarController?.selectedIndex else { return } // 遍历TabBar的子视图,找到对应选中的Item视图 for (index, view) in subviews.enumerated() { // 系统TabBar的Item视图是UIControl类型,通过索引匹配选中项 if view is UIControl, index == selectedIndex { // 创建圆圈标记图层 let markerLayer = CAShapeLayer() markerLayer.name = markerLayerName // 1. 画圆圈:中心在Item视图中心,半径可自定义 let circlePath = UIBezierPath( arcCenter: CGPoint(x: view.bounds.midX, y: view.bounds.midY), radius: 22, // 圆圈半径 startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true ) // 2. 或者画方框:使用inset调整边框与Item的间距 // let rectPath = UIBezierPath(rect: view.bounds.insetBy(dx: 6, dy: 6)) markerLayer.path = circlePath.cgPath markerLayer.strokeColor = UIColor.systemBlue.cgColor // 边框颜色 markerLayer.fillColor = UIColor.clear.cgColor // 填充透明 markerLayer.lineWidth = 2 // 边框宽度 view.layer.addSublayer(markerLayer) } } } // 监听选中状态变化,触发重新布局更新标记 override func setSelectedItem(_ selectedItem: UITabBarItem?) { super.setSelectedItem(selectedItem) setNeedsLayout() } }
- 在TabBarController中使用自定义TabBar:
class CustomTabBarController: UITabBarController { override func viewDidLoad() { super.viewDidLoad() // 替换系统TabBar为自定义的 tabBar = CustomTabBar() } }
这种方法优势是完全可控,可根据需求动态修改标记样式;缺点是需要处理系统TabBar子视图的遍历逻辑,要注意适配不同iOS版本的视图结构变化。
方法三:利用UITabBarAppearance(iOS13+官方推荐)
从iOS13开始,苹果提供了UITabBarAppearance统一配置TabBar样式,我们可以通过自定义选中态的背景图实现圆圈/方框标记。
步骤:
- 创建带圆圈/方框的自定义背景图(代码绘制,无需资源文件):
extension UIImage { static func createMarkerImage(size: CGSize, color: UIColor, lineWidth: CGFloat = 2) -> UIImage { UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale) let context = UIGraphicsGetCurrentContext()! // 画圆圈 let circlePath = UIBezierPath( arcCenter: CGPoint(x: size.width/2, y: size.height/2), radius: min(size.width, size.height)/2 - lineWidth, startAngle: 0, endAngle: CGFloat.pi*2, clockwise: true ) color.setStroke() circlePath.lineWidth = lineWidth circlePath.stroke() let image = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return image } }
- 配置TabBarAppearance并应用到TabBar:
class CustomTabBarController: UITabBarController { override func viewDidLoad() { super.viewDidLoad() let appearance = UITabBarAppearance() // 配置选中态的样式 let selectedAppearance = UITabBarItemAppearance() // 设置选中时的图标颜色 selectedAppearance.iconColor = .systemBlue // 设置自定义的圆圈背景图 selectedAppearance.backgroundImage = UIImage.createMarkerImage( size: CGSize(width: 60, height: 60), color: .systemBlue ) // 应用选中态配置到堆叠布局(适合大多数场景) appearance.stackedLayoutAppearance.selected = selectedAppearance // 应用配置到TabBar tabBar.standardAppearance = appearance // iOS15+需要额外设置scrollEdgeAppearance,适配滚动到顶部的情况 if #available(iOS 15.0, *) { tabBar.scrollEdgeAppearance = appearance } } }
这种方法优势是符合苹果设计规范,适配性更好;缺点是仅支持iOS13及以上版本。
内容的提问来源于stack exchange,提问作者Trgrit Tjforce
相关产品推荐
相关产品推荐

