SwiftUI 自定义 Shape:实现顶部圆角矩形 RoundedTopRectangle

在 SwiftUI 里,如果你只想要一个"顶部两个角是圆角,底部是直角"的矩形,第一反应可能是用 .cornerRadius()

.cornerRadius() 会同时作用在四个角,没办法单独控制某些角,这时候就需要自定义 Shape

这篇文章,我们就从零实现一个 RoundedTopRectangle,并详细解释绘制的每一步。

为什么用 Shape

在 SwiftUI 里,Shape 是最底层的绘制单位 。它的 path(in:) 方法允许我们在给定的矩形范围内,自己决定如何绘制路径。

你可以理解成:给了我们一张画布(rect),我们要在上面用"画笔"按顺序描出路径。

  • move(to:) 就是把画笔移动到某个点(不画线)。
  • addLine(to:) 是画直线。
  • addArc(...) 是画圆弧。
  • closeSubpath() 是闭合路径,自动连回起点。

这样拼起来,就能绘制出任何你想要的形状。

完整代码

less 复制代码
import SwiftUI

struct RoundedTopRectangle: Shape {
    func path(in rect: CGRect) -> Path {
        let width = rect.width
        let height = rect.height
        let cornerRadius: CGFloat = 24

        var path = Path()

        // 1. 起点:从左上角圆弧的下方开始 (0, cornerRadius)
        path.move(to: CGPoint(x: 0, y: cornerRadius))

        // 2. 左上角圆弧:180° → 270°
        path.addArc(
            center: CGPoint(x: cornerRadius, y: cornerRadius),
            radius: cornerRadius,
            startAngle: .degrees(180),
            endAngle: .degrees(270),
            clockwise: false
        )

        // 3. 顶部水平线:连接到右上角圆弧的起点
        path.addLine(to: CGPoint(x: width - cornerRadius, y: 0))

        // 4. 右上角圆弧:270° → 360°
        path.addArc(
            center: CGPoint(x: width - cornerRadius, y: cornerRadius),
            radius: cornerRadius,
            startAngle: .degrees(270),
            endAngle: .degrees(360),
            clockwise: false
        )

        // 5. 右侧直线到底部
        path.addLine(to: CGPoint(x: width, y: height))

        // 6. 底部直线到左下角
        path.addLine(to: CGPoint(x: 0, y: height))

        // 7. 左侧直线回到圆弧起点
        path.addLine(to: CGPoint(x: 0, y: cornerRadius))

        // 8. 闭合路径
        path.closeSubpath()

        return path
    }
}

角度怎么理解?

在 SwiftUI 里,角度是数学坐标系的标准方向

  • 0° = 水平方向(正右)
  • 90° = 垂直方向(正上)
  • 180° = 水平方向(正左)
  • 270° = 垂直方向(正下)

所以:

  • 左上角圆弧,我们要从左往下画:180° → 270°
  • 右上角圆弧,我们要从下往右画:270° → 360°

这就是为什么要用这些角度范围。

效果展示

VStack 里放一个 RoundedTopRectangle

css 复制代码
struct ContentView: View {
    var body: some View {
        VStack {
            Spacer()
            RoundedTopRectangle()
                .fill(Color.blue)
                .frame(height: 300)
                .shadow(radius: 5)
        }
        .edgesIgnoringSafeArea(.bottom)
    }
}

运行效果:

  • 底部是一个蓝色矩形
  • 顶部两个角是圆角,底部两个角是直角
  • 非常适合做 Bottom Sheet、播放器控制面板、支付弹窗等 UI。

改进思路

  1. 参数化圆角

    目前 cornerRadius 写死为 24,可以改成一个参数:

    swift 复制代码
    struct RoundedTopRectangle: Shape {
        var cornerRadius: CGFloat = 24
        func path(in rect: CGRect) -> Path { ... }
    }
  2. 只控制某些角

    如果你想要"底部圆角,顶部直角",只需要调整绘制的顺序,把圆弧放到底部。

  3. 支持可配置的四角圆角

    甚至可以写成一个更通用的 CustomRoundedRectangle,传入 [topLeft: true, topRight: false, ...] 这样的布尔配置,来决定哪些角是圆角。

总结

  • .cornerRadius() 方便,但太"平均"。
  • Shape 给了我们精细的控制,可以定义任何奇怪的矩形。
  • 理解 Path + 坐标 + 角度,你就能自由画出想要的图形。

自定义 Shape 是 SwiftUI 的隐藏宝藏,玩明白之后,不仅可以做圆角矩形,还能画波浪、曲线、对角线圆角等各种有趣的 UI。

相关推荐
末代iOS程序员华仔2 小时前
iOS上架海外工具类应用合规指南:避免封号与下架风险
flutter·ios·swift
末代iOS程序员华仔4 小时前
Flutter 开发 iOS App 上架全流程与常见问题分析
flutter·ios
末代iOS程序员华仔4 小时前
Flutter开发iOS海外工具类应用上架合规指南与风险规避
flutter·ios
AI云海18 小时前
iOS 多 Target 打包、UAT/生产测试与上架 App Store 全流程指南
ios
阿里超级工程师20 小时前
最新快速申请ios打包证书和profile文件步骤
ios·打包证书
2501_915909061 天前
iOS 应用反调试技详解术 检测调试器的原理与防护实践
android·ios·小程序·https·uni-app·iphone·webview
游戏开发爱好者81 天前
TraceEagle 代理抓包详解,无感代理、去证书绑定与 HTTP/3 解密能力解析
网络协议·计算机网络·网络安全·ios·adb·https·udp
aiopencode1 天前
SwiftUI Introspect生产环境完全指南:为什么它是安全可靠的选择
后端·ios
for_ever_love__1 天前
iOS: 网络管理单例
学习·ios·objective-c
00后程序员张1 天前
iOS加固技术路线全面解析:Bitcode模式、源码模式与汇编模式对比及爱加密优势
android·汇编·ios·小程序·uni-app·cocoa·iphone