SwiftUI实现带居中圆角按钮的自定义TabBar布局优化
调整SwiftUI自定义TabBar布局以缩小间距的解决方案
以下是针对你的需求,对现有SwiftUI代码的具体调整方案,通过修改系统TabBar样式、自定义曲线形状和中间按钮尺寸来实现紧凑的TabBar布局:
关键修改点
1. 缩小系统TabItem的间距与边距
在主视图初始化时,直接修改UITabBar的外观属性,调整TabItem的间距、填充方式和宽度,消除多余空白:
init() { // 缩小TabItem之间的间距 UITabBar.appearance().itemSpacing = 6 // 设置TabItem填充整个TabBar宽度,消除左右边距 UITabBar.appearance().itemPositioning = .fill // 自定义每个TabItem的宽度,根据数量适配 let itemCount = CGFloat(5) UITabBar.appearance().itemWidth = UIScreen.main.bounds.width / itemCount - 12 }
2. 缩小中间圆形按钮的尺寸与底部间距
修改TabSelection中的圆形按钮,缩小尺寸并调整偏移量,让按钮更贴合TabBar:
Circle().foregroundColor(.black) // 将按钮尺寸缩小为原高度的80% .frame(height: height * 0.8) .aspectRatio(contentMode: .fit) .shadow(radius: 4) // 向上偏移按钮,缩小与底部的间距 .offset(y: height * 0.1) .overlay(Image(systemName: item.icon) // 缩小图标字体 .font(.title2) .foregroundColor(.white))
3. 调整自定义曲线的紧凑度
修改Curve形状的路径控制点,让曲线的左右范围更窄,减少空白区域:
func path(in rect: CGRect) -> Path { // 降低曲线的凸起高度 let h = rect.maxY * 0.6 return Path { $0.move(to: .zero) // 让曲线左起点更靠近中间 $0.addLine(to: CGPoint(x: rect.midX * 0.6, y: rect.minY)) // 调整曲线控制点,缩小曲线宽度 $0.addCurve(to: CGPoint(x: rect.midX, y: h), control1: CGPoint(x: rect.midX * 0.7, y: rect.minY), control2: CGPoint(x: rect.midX * 0.8, y: h)) $0.addCurve(to: CGPoint(x: rect.midX * 1.4, y: rect.minY), control1: CGPoint(x: rect.midX * 1.2, y: h), control2: CGPoint(x: rect.midX * 1.3, y: rect.minY)) // 让曲线右起点更靠近中间 $0.addLine(to: CGPoint(x: rect.maxX, y: rect.minY)) } }
4. 压缩TabSelection的整体高度
在TabSelection中,调整曲线的最大高度,降低TabBar的整体高度:
Curve() .frame(maxWidth: .infinity, maxHeight: height * 0.8) // 缩小曲线高度 .foregroundColor(item.color)
修改后的完整代码
import SwiftUI struct TestReorderTabItemsPerSelection: View { @State private var selection: String = "house" @State private var tbHeight = CGFloat.zero // 初始化时调整系统TabBar外观 init() { UITabBar.appearance().itemSpacing = 6 UITabBar.appearance().itemPositioning = .fill let itemCount = CGFloat(5) UITabBar.appearance().itemWidth = UIScreen.main.bounds.width / itemCount - 12 } struct Item { let title: String let color: Color let icon: String } @State var items = [ Item(title: "folder", color: .red, icon: "folder"), Item(title: "eraser", color: .red, icon: "eraser.fill"), Item(title: "cart", color: .red, icon: "cart"), Item(title: "house", color: .blue, icon: "house"), Item(title: "car", color: .green, icon: "car"), ] var selected: Item { items.first { $0.title == selection } ?? items[0] } var body: some View { ZStack(alignment: .bottom) { TabView(selection: $selection) { ForEach(items, id: \.title) { item in TabContent(height: $tbHeight) { item.color } .tabItem { Image(systemName: item.icon) Text(item.title) } } } TabSelection(height: tbHeight, item: selected) } } struct TabSelection: View { let height: CGFloat let item: Item var body: some View { VStack { Spacer() Curve() // 缩小曲线最大高度 .frame(maxWidth: .infinity, maxHeight: height * 0.8) .foregroundColor(item.color) } .ignoresSafeArea() .overlay( Circle().foregroundColor(.black) // 缩小圆形按钮尺寸 .frame(height: height * 0.8) .aspectRatio(contentMode: .fit) .shadow(radius: 4) // 调整按钮偏移,缩小与底部间距 .offset(y: height * 0.1) .overlay(Image(systemName: item.icon) // 缩小图标字体 .font(.title2) .foregroundColor(.white)) , alignment: .bottom) } } struct TabContent<V: View>: View { @Binding var height: CGFloat @ViewBuilder var content: () -> V var body: some View { GeometryReader { gp in content() .onAppear { height = gp.safeAreaInsets.bottom } .onChange(of: gp.size, { height = gp.safeAreaInsets.bottom }) } } } struct Curve: Shape { func path(in rect: CGRect) -> Path { // 降低曲线高度 let h = rect.maxY * 0.6 return Path { $0.move(to: .zero) // 左起点更靠近中间 $0.addLine(to: CGPoint(x: rect.midX * 0.6, y: rect.minY)) // 调整曲线控制点,缩小宽度 $0.addCurve(to: CGPoint(x: rect.midX, y: h), control1: CGPoint(x: rect.midX * 0.7, y: rect.minY), control2: CGPoint(x: rect.midX * 0.8, y: h)) $0.addCurve(to: CGPoint(x: rect.midX * 1.4, y: rect.minY), control1: CGPoint(x: rect.midX * 1.2, y: h), control2: CGPoint(x: rect.midX * 1.3, y: rect.minY)) // 右起点更靠近中间 $0.addLine(to: CGPoint(x: rect.maxX, y: rect.minY)) } } } } struct TestReorderTabItemsPerSelection_Previews: PreviewProvider { static var previews: some View { TestReorderTabItemsPerSelection() } }
效果说明
修改后你将得到:
- 系统TabItem间距大幅缩小,左右无多余边距
- 中间圆形按钮尺寸更小,与底部贴合更紧密
- 自定义曲线范围更窄,TabBar整体高度更低,布局更紧凑
内容的提问来源于stack exchange,提问作者Sham Dhiman
相关产品推荐
相关产品推荐

