View — Shapes

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


1. 什么是 Shape 体系结构? #

1.1 Shape 协议 #

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

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 填充颜色 #

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

3.2 描边(Stroke) #

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

3.3 渐变填充 #

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 阴影 #

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 可以用作裁剪视图的蒙版。

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

4. 自定义 Shape #

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

4.1 绘制一个三角形 #

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 参数,我们可以实现灵活的多边形(五边形、六边形等)。

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)
    }
}

5. 组合 Shapes #

5.1 叠加多个 Shape #

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

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 都能够提供强大的支持。

本文共 1748 字,上次修改于 Jan 8, 2025