跳至正文
View — Shapes

Shapes

在 SwiftUI 中,Shapes 是定义用户界面中几何形状的核心工具之一。通过使用 Shape 协议或已有的 Shape 类型,可以轻松创建、组合、裁剪和装饰各种形状。SwiftUI 提供了一系列内置形状工具,如 RectangleEllipseCapsule 等,并允许开发者通过实现 Shape 协议来自定义形状。Shape 的灵活性使其在创建按钮背景、图像裁剪、容器框架和装饰性 UI 元素中非常重要。


1. 什么是 Shape 体系结构?

1.1 Shape 协议

Shape 是 SwiftUI 中的一个协议。遵循这个协议的类型必须实现以下方法:

swift
protocol Shape {
    func path(in rect: CGRect) -> Path
}

核心要点:

  • path(in rect:) 方法:用来描述形状的路径(Path),并接收一个 CGRect 来定义绘制的区域。
  • Path 是用于描述几何图形的 SwiftUI 数据结构,允许用绘点、线段、曲线等方式定义自定义形状。

1.2 Shape 的核心行为

  • 绘制形状:使用 SwiftUI 的 Canvas,形状被绘制在指定的绘图框 CGRect 中。
  • 填充形状:形状可以使用颜色、图像或渐变进行填充(.fill())。
  • 描边(边框):可以使用 .stroke() 定义边框颜色和宽度。
  • 裁剪:可以使用形状作为视图的蒙版(clipShape())。

2. 内置 Shape 类型

SwiftUI 提供了一系列内置的形状,这些形状可以立即使用,并通过 Frame、填充或修饰符调整外观:

名称描述用例
Rectangle一个基本矩形。用作背景、容器、装饰元素。
RoundedRectangle带圆角的矩形,通过 cornerRadius 控制圆角半径。按钮、标签、圆角背景。
Circle一个标准的圆形(宽高等于 Frame 时)。欢迎页面的头像、圆形裁剪区域。
Ellipse自动适应 Frame 尺寸的椭圆形(长短轴根据比例调整)。装饰背景、裁剪、进度条形状。
Capsule圆角矩形,类似于药丸形状,宽高比不等时表现为椭圆。创建按钮、Tag 样式化背景。
Triangle没有内置 Triangle,可通过实现 Shape 协议定义一个三角形。装饰元素、指示性标志。
Polygon需通过自定义 Shape 创建多边形(四边形、五边形等)。创建图表、动画图形组件。
Path自由绘制的用于定义复杂路径的形状。创建高度定制化的形状,例如波浪、星形、多边形等。

3. Shape 的常见操作

通过修改器,SwiftUI 提供了一些常见的形状操作支持,如填充、描边、添加渐变、阴影等。

3.1 填充颜色

swift
struct FillExample: View {
    var body: some View {
        Circle()
            .fill(Color.blue)
            .frame(width: 100, height: 100)
    }
}

3.2 描边(Stroke)

swift
struct StrokeExample: View {
    var body: some View {
        RoundedRectangle(cornerRadius: 20)
            .stroke(Color.red, lineWidth: 5) // 描边颜色和宽度
            .frame(width: 150, height: 100)
    }
}

3.3 渐变填充

swift
struct GradientFillExample: View {
    var body: some View {
        Ellipse()
            .fill(
                LinearGradient(
                    gradient: Gradient(colors: [.blue, .green]),
                    startPoint: .leading, // 渐变从左
                    endPoint: .trailing   // 渐变到右
                )
            )
            .frame(width: 200, height: 100)
    }
}

3.4 阴影

swift
struct ShadowExample: View {
    var body: some View {
        Capsule()
            .fill(Color.orange)
            .frame(width: 150, height: 50)
            .shadow(color: .black.opacity(0.3), radius: 10, x: 5, y: 5) // 添加阴影
    }
}

3.5 裁剪蒙版(Clip Shape)

Shape 可以用作裁剪视图的蒙版。

swift
struct ClipShapeExample: View {
    var body: some View {
        Image("exampleImage")
            .resizable()
            .scaledToFit()
            .frame(width: 200, height: 200)
            .clipShape(Circle()) // 使用 Circle 裁剪图片
    }
}

4. 自定义 Shape

通过实现 Shape 协议,开发者可以绘制自定义形状。

4.1 绘制一个三角形

swift
struct Triangle: Shape {
    func path(in rect: CGRect) -> Path {
        Path { path in
            path.move(to: CGPoint(x: rect.midX, y: rect.minY))  // 顶点
            path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY)) // 右下
            path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY)) // 左下
            path.closeSubpath() // 闭合路径
        }
    }
}

struct TriangleExample: View {
    var body: some View {
        Triangle()
            .fill(Color.blue)
            .frame(width: 150, height: 150)
    }
}

4.2 创建一个多边形

通过可配置的 sideCount 参数,我们可以实现灵活的多边形(五边形、六边形等)。

swift
struct Polygon: Shape {
    let sides: Int

    func path(in rect: CGRect) -> Path {
        guard sides >= 3 else { return Path() }  // 至少需要三边

        let center = CGPoint(x: rect.midX, y: rect.midY)
        let radius = min(rect.width, rect.height) / 2
        let angleIncrement = 2 * .pi / CGFloat(sides)

        return Path { path in
            for i in 0..<sides {
                let angle = CGFloat(i) * angleIncrement - .pi / 2
                let point = CGPoint(
                    x: center.x + radius * cos(angle),
                    y: center.y + radius * sin(angle)
                )
                if i == 0 {
                    path.move(to: point)
                } else {
                    path.addLine(to: point)
                }
            }
            path.closeSubpath() // 闭合路径
        }
    }
}

struct PolygonExample: View {
    var body: some View {
        Polygon(sides: 5) // 五边形
            .stroke(Color.purple, lineWidth: 2)
            .frame(width: 200, height: 200)
    }
}

4.3 addArc

在 Apple 的开发框架(如 ​Core Graphics​ 或 ​SwiftUI)中,path.addArc 是一个用于向绘图路径(CGPath 或 Path)中添加圆弧的方法。它允许你通过指定圆心、半径、起始角度和结束角度来精确绘制圆弧或圆形。


核心参数解析

以 Swift 的 Core Graphics 为例,方法的典型定义如下:

swift
// Core Graphics 中的 CGPath 方法
func addArc(
    center: CGPoint,      // 圆心坐标
    radius: CGFloat,      // 圆弧半径
    startAngle: CGFloat,  // 起始角度(弧度)
    endAngle: CGFloat,    // 结束角度(弧度)
    clockwise: Bool       // 是否顺时针绘制
)

关键细节​:

  1. 角度单位​:参数 startAngle 和 endAngle 使用弧度制,而非角度制。

    • 例如:0 弧度对应右侧(3点钟方向),π/2 对应顶部(12点钟方向)。
  2. 坐标系方向​:

    • 在 iOS/macOS 的绘图坐标系中,​Y 轴向下延伸​(与数学坐标系相反)。
    • 因此,clockwise: true 在屏幕上可能表现为逆时针方向​(需特别注意)。

代码示例

在 Core Graphics 中绘制一个 ​90° 圆弧​(从右侧到顶部):

swift
let path = CGMutablePath()
path.addArc(
    center: CGPoint(x: 100, y: 100),  // 圆心坐标
    radius: 50,                       // 半径 50
    startAngle: 0,                    // 起始角度:右侧(0弧度)
    endAngle: .pi/2,                  // 结束角度:顶部(π/2弧度)
    clockwise: true                   // "顺时针"(实际为逆时针方向)
)

// 绘制到图形上下文
let context = UIGraphicsGetCurrentContext()
context?.addPath(path)
context?.strokePath()

常见用途

  1. 绘制扇形或圆环​:

    • 结合 move(to: center) 和 addLine(to: center),闭合路径可形成扇形。
    • 通过设置 lineWidth 和 stroke,可绘制空心圆环。
  2. 动态进度条​:

    • 根据进度值动态计算 endAngle,绘制圆弧表示加载进度。
  3. 复杂图形的一部分​:

    • 结合直线(addLine)、贝塞尔曲线(addCurve)等,构建自定义形状。

注意事项

  1. 角度方向陷阱​:
    若发现圆弧方向与预期相反,尝试将 clockwise 参数取反(false → true 或反之)。

  2. 闭合路径​:
    若需绘制闭合图形(如扇形),需手动添加线条回到圆心或调用 closePath()

  3. SwiftUI 中的等效方法​:
    在 SwiftUI 的 Path 中,使用 addArc 或 arc 方法,语法略有不同:

    swift
    Path { path in
        path.addArc(
            center: CGPoint(x: 100, y: 100),
            radius: 50,
            startAngle: .degrees(0),
            endAngle: .degrees(90),
            clockwise: true
        )
    }
    

数学原理

圆弧的数学定义基于极坐标系:

  • 圆心​:确定圆弧位置。
  • 半径​:确定圆弧大小。
  • 起始/结束角度​:控制圆弧覆盖的角度范围。

通过组合多个圆弧和路径操作,可实现复杂的图形绘制需求。


5. 组合 Shapes

5.1 叠加多个 Shape

ZStack 可以用来叠加多个形状。

swift
struct CombinedShapesExample: View {
    var body: some View {
        ZStack {
            Circle().fill(Color.blue).frame(width: 150, height: 150)
            RoundedRectangle(cornerRadius: 20)
                .fill(Color.orange)
                .frame(width: 100, height: 100)
        }
    }
}

5.2 自定义复合效果

通过形状的组合,可以绘制更加复杂的图形。


6. Shapes 的应用场景

  1. 背景设计: 创建按钮背景、卡片背景、标签等样式化元素。
  2. 裁剪效果: 用于裁剪图片或视图内容。
  3. 动态图形: 结合 @State 和动画实现有趣的交互式效果。
  4. 图表组件: 绘制饼图、柱状图、折线图等。
  5. 装饰性元素: 增强 UI 丰富性,例如分隔器、波浪边框等。
  6. 状态显示: 创建进度条、加载指示器等。

总结

SwiftUI 的 Shapes 体系是一个强大的视觉构建工具:

  1. 基础形状:提供 RectangleCircleEllipse 等易用形状,用于常见的 UI 元素。
  2. 高度可定制性:通过实现 Shape 协议,开发者可以自由绘制自定义形状。
  3. 多样化修饰器:提供渐变、描边、阴影等修饰器丰富视觉效果。
  4. 与动画结合Shape 与 SwiftUI 的动画特性(如 withAnimationGeometryEffect)无缝兼容,支持动态变化。

无论是简单的 UI 元素还是复杂的装饰内容,Shapes 都能够提供强大的支持。

本文共 2030 字,创建于 Jan 8, 2025

相关标签:SwiftUI, Xcode, ByAI

评论

博客助手

正在打开博客助手…