iOS15.5(Xcode13.4.1)中SwiftUI TabBar选中项紫色背景框实现方法
问题描述
我正在iOS15.5(Xcode13.4.1)上开发SwiftUI应用,希望实现带有选中项紫色背景框的TabBar(目标样式:选中的Tab项被紫色圆角框包裹),但当前实现的TabBar无该紫色框(当前样式:选中项仅图标/文字变色,无背景框)。
当前实现代码:
import SwiftUI var tabcolor = Color(red: 120/255, green: 57/255, blue: 62/255) struct VistaMain: View { @EnvironmentObject var vm: ViewModel @State var seleccion : Int = 0 var colorSeleccion: Color = Color(red: 73 / 255, green: 82 / 255, blue: 189 / 255) init(){ UITabBar.appearance().barTintColor = UIColor(red: 56/255, green: 57/255, blue: 62/255, alpha: 0) UITabBar.appearance().backgroundColor = UIColor(red: 56/255, green: 57/255, blue: 62/255, alpha: 1) } var body: some View { //InicioView() Color(red: 48 / 255, green: 49 / 255, blue: 54 / 255) .ignoresSafeArea() .overlay( TabView(selection: $seleccion){ NuevoExperimentoView() .tabItem{ Label("Nuevo exp", systemImage: "list.bullet.rectangle.portrait")//.background( frame(width: 30, height: 30)) } .tag(0) NuevoExperimentoView() .tabItem{ Label("Nuevo exp", systemImage: "list.bullet.rectangle.portrait") } .tag(1) NuevoExperimentoView() .tabItem{ Label("Nuevo exp", systemImage: "list.bullet.rectangle.portrait") } .tag(2) VistaPerfilUsuario(usuarioCurrent: vm.usuariosArray[0], foto: UIImage(data: vm.usuariosArray[0].foto!)!).environmentObject(ViewModel()) .tabItem{ Label("Perfil", systemImage: "person.circle.fill") } .tag(4) } ) } }
请问如何实现该紫色背景框?此功能在该iOS版本是否可行?
解决方案
可行性说明
iOS15.5的原生SwiftUI TabView没有直接提供给选中Tab项添加背景框的API,无法通过UITabBar.appearance()配置实现该效果,需要通过自定义TabBar的方式来达成需求。
实现步骤
- 隐藏原生TabBar,改用自定义底部导航栏替代
- 统一管理Tab项数据,基于选中状态渲染紫色背景框
- 绑定选中状态,切换对应页面视图
完整代码示例
import SwiftUI var tabcolor = Color(red: 120/255, green: 57/255, blue: 62/255) struct VistaMain: View { @EnvironmentObject var vm: ViewModel @State var seleccion: Int = 0 // 选中项紫色背景色 let colorSeleccion: Color = Color(red: 73 / 255, green: 82 / 255, blue: 189 / 255) // TabBar背景色 let tabBarBgColor: Color = Color(red: 56/255, green: 57/255, blue: 62/255) // 统一管理Tab项数据 private let tabItems: [(title: String, icon: String, tag: Int)] = [ ("Nuevo exp", "list.bullet.rectangle.portrait", 0), ("Nuevo exp", "list.bullet.rectangle.portrait", 1), ("Nuevo exp", "list.bullet.rectangle.portrait", 2), ("Perfil", "person.circle.fill", 4) ] var body: some View { ZStack(alignment: .bottom) { // 页面背景 Color(red: 48 / 255, green: 49 / 255, blue: 54 / 255) .ignoresSafeArea() // 根据选中状态切换页面 switch seleccion { case 0: NuevoExperimentoView() case 1: NuevoExperimentoView() case 2: NuevoExperimentoView() case 4: VistaPerfilUsuario(usuarioCurrent: vm.usuariosArray[0], foto: UIImage(data: vm.usuariosArray[0].foto!)!) .environmentObject(ViewModel()) default: NuevoExperimentoView() } // 自定义TabBar HStack(spacing: 0) { ForEach(tabItems, id: \.tag) { item in Button(action: { seleccion = item.tag }) { VStack(spacing: 4) { Image(systemName: item.icon) Text(item.title) .font(.caption) } .foregroundColor(seleccion == item.tag ? .white : .gray) .padding(.vertical, 8) .padding(.horizontal, 12) // 选中时显示紫色背景框 .background(seleccion == item.tag ? colorSeleccion : Color.clear) .cornerRadius(8) } .frame(maxWidth: .infinity) } } .padding(.horizontal, 16) .padding(.vertical, 8) .background(tabBarBgColor) .ignoresSafeArea(edges: .bottom) } .onAppear { // 隐藏原生TabBar UITabBar.appearance().isHidden = true } } } // 以下为编译所需的占位视图/模型 struct NuevoExperimentoView: View { var body: some View { Text("Nuevo Experimento") } } struct VistaPerfilUsuario: View { let usuarioCurrent: ViewModel.Usuario let foto: UIImage @EnvironmentObject var vm: ViewModel var body: some View { Text("Perfil") } } class ViewModel: ObservableObject { struct Usuario: Identifiable { let id = UUID() let foto: Data? } @Published var usuariosArray = [Usuario(foto: UIImage(systemName: "person")?.pngData())] }
代码说明
- 用
tabItems数组统一管理Tab项的标题、图标和标签,便于后续维护修改 - 通过
ZStack将页面内容与自定义TabBar叠加,TabBar固定在底部 - 每个Tab项是可点击的
Button,点击时更新选中状态 - 利用
background修饰符根据选中状态动态显示紫色背景框,搭配cornerRadius实现圆角效果 - 隐藏原生
UITabBar,避免与自定义导航栏冲突
内容的提问来源于stack exchange,提问作者Dox
相关产品推荐
相关产品推荐

