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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 14:22:32