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

SwiftUI如何实现顶部圆角底部外凸曲线的自定义TabBar?

实现SwiftUI自定义反向圆角TabBar

自定义TabBar样式

我想要在SwiftUI中实现如图所示的自定义TabBar形状:顶部左右角为常规圆角,底部左右角为反向曲线(向外凸起的独特造型)。

我尝试过使用clipShape搭配简单的RoundedRectangle,但它无法实现底部角落的反向曲线效果。请问如何创建符合图中样式的SwiftUI自定义Shape?

我的尝试代码:

//
//  CustomTabBar.swift
//  skill
//
//  Created by Chetan Patil on 06/12/24.
//

import SwiftUI

struct CustomTabBar: View {
    @State private var selectedTab: Tab = .favourites // 跟踪选中标签的状态
    
    enum Tab {
        case favourites, accounts, payments, deposits
    }

    var body: some View {
        VStack(spacing: 0) {
            // 标签栏内容
            
            // 自定义Tab Bar
            HStack {
                tabItem(title: "Favourites", isSelected: selectedTab == .favourites) {
                    selectedTab = .favourites
                }
                
                tabItem(title: "Accounts", isSelected: selectedTab == .accounts) {
                    selectedTab = .accounts
                }
                tabItem(title: "Payments", isSelected: selectedTab == .payments) {
                    selectedTab = .payments
                }
                tabItem(title: "Deposits", isSelected: selectedTab == .deposits) {
                    selectedTab = .deposits
                }
            }
            .background(Color(red: 0/255, green: 64/255, blue: 143/255))
           
            // 内容区域
            TabView(selection: $selectedTab) {
                FavouritesView()
                    .tag(Tab.favourites)
                AccountsView()
                    .tag(Tab.accounts)
                PaymentsView()
                    .tag(Tab.payments)
                DepositsView()
                    .tag(Tab.deposits)
            }
            .frame(maxWidth: .infinity, maxHeight: 400)
            
        }
        .ignoresSafeArea(edges: .bottom) // 让TabBar延伸到底部安全区外
    }

    // 单个标签项视图
    private func tabItem(title: String, isSelected: Bool, action: @escaping () -> Void) -> some View {
        Button(action: action) {
            Text(title)
                .font(.system(size: 14, weight: isSelected ? .bold : .regular))
                .foregroundColor(isSelected ? .black : .gray)
                .padding(.vertical, 12)
                .frame(maxWidth: .infinity)
        }
        .background(isSelected ? Color.white : Color.clear) // 高亮选中的标签
        .clipShape(
            .rect(
                topLeadingRadius: 10,
                bottomLeadingRadius: -10,
                bottomTrailingRadius: -10,
                topTrailingRadius: 10
            )
        )
    }
}


// 各标签页的示例视图
struct FavouritesView: View {
    var body: some View {
        Text("收藏页")
            .frame(maxWidth: .infinity, maxHeight: 400)
            .background(Color.white)
    }
}


struct AccountsView: View {
    var body: some View {
        Text("账户页")
            .frame(maxWidth: .infinity, maxHeight: 400)
            .background(Color.white)
    }
}

struct PaymentsView: View {
    var body: some View {
        Text("支付页")
            .frame(maxWidth: .infinity, maxHeight: 400)
            .background(Color.white)
    }
}

struct DepositsView: View {
    var body: some View {
        Text("存款页")
            .frame(maxWidth: .infinity, maxHeight: 400)
            .background(Color.white)
    }
}


#Preview {
    CustomTabBar()
}

解决方案:自定义Shape实现反向圆角

要实现底部向外凸起的反向曲线,需要自定义一个遵循Shape协议的结构体,手动绘制路径:

struct CustomTabBarShape: Shape {
    let cornerRadius: CGFloat
    
    func path(in rect: CGRect) -> Path {
        var path = Path()
        
        // 绘制顶部左圆角
        path.move(to: CGPoint(x: rect.minX + cornerRadius, y: rect.minY))
        path.addArc(center: CGPoint(x: rect.minX + cornerRadius, y: rect.minY + cornerRadius),
                    radius: cornerRadius,
                    startAngle: .degrees(270),
                    endAngle: .degrees(180),
                    clockwise: false)
        
        // 绘制顶部右圆角
        path.addLine(to: CGPoint(x: rect.maxX - cornerRadius, y: rect.minY))
        path.addArc(center: CGPoint(x: rect.maxX - cornerRadius, y: rect.minY + cornerRadius),
                    radius: cornerRadius,
                    startAngle: .degrees(270),
                    endAngle: .degrees(0),
                    clockwise: false)
        
        // 绘制底部右反向圆角(向外凸)
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - cornerRadius))
        path.addArc(center: CGPoint(x: rect.maxX - cornerRadius, y: rect.maxY - cornerRadius),
                    radius: cornerRadius,
                    startAngle: .degrees(0),
                    endAngle: .degrees(90),
                    clockwise: false)
        
        // 绘制底部左反向圆角(向外凸)
        path.addLine(to: CGPoint(x: rect.minX + cornerRadius, y: rect.maxY))
        path.addArc(center: CGPoint(x: rect.minX + cornerRadius, y: rect.maxY - cornerRadius),
                    radius: cornerRadius,
                    startAngle: .degrees(90),
                    endAngle: .degrees(180),
                    clockwise: false)
        
        path.closeSubpath()
        return path
    }
}

然后修改原代码中的TabBar背景部分,应用这个自定义Shape:

HStack {
    // 原tabItem代码保持不变
}
.background(Color(red: 0/255, green: 64/255, blue: 143/255))
.clipShape(CustomTabBarShape(cornerRadius: 10)) // 添加这一行应用自定义形状

如果需要调整反向曲线的弧度,只需要修改cornerRadius参数即可。

内容的提问来源于stack exchange,提问作者Chetan patil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 19:28:09