SwiftUI绘画视图Canvas
SwiftUI绘画视图Canvas

SwiftUI绘画视图Canvas

Canvas 是 SwiftUI 中引入的一种强大的绘图视图,允许Swift 代码高效地绘制自定义的图形、路径和视觉效果。它的功能类似于 Core Graphics,但使用了 SwiftUI 风格的声明式语法。

核心特点

1、轻松绘制自定义图形

通过 Canvas,可以绘制路径、图像、文字等内容,而无需直接操作 Core Graphics。

2、高性能

Canvas 的绘图由底层 Metal 或 Core Animation 提供支持,性能优化良好,适合动态内容。

3、支持动画和动态变化

与 SwiftUI 的动画系统无缝结合,可以实现实时更新的动态绘图。

4、可使用TimelineView

TimelineView 配合,可以创建时间驱动的动画内容。

Canvas 的组成

1、Canvas 初始化器

Canvas { context, size in
    // 在此处绘制内容
}

context:表示绘图上下文,用于绘制内容(如路径、文本、图像)。

size:表示 Canvas 的尺寸,绘制内容应基于此动态适配。

2、绘制内容的方法

填充图形:context.fill(Path, with:)

context.fill(
    Path(CGRect(origin: .zero, size: size)),
    with: .color(.blue.opacity(0.2))
)

描边路径:context.stroke(Path, with:, lineWidth:)

context.stroke(Path(ellipseIn: circleRect), with: .color(.red), lineWidth: 5)

绘制图片:context.draw(Image, in:)

绘制文本:context.draw(Text, at:)

3、支持的样式

Color、Gradient 等多种颜色和样式。

基本用法

1、简单示例:绘制圆形和直线

以下是一个基本示例,展示如何在 Canvas 中绘制自定义图形。

import SwiftUI

struct ContentView: View {
    var body: some View {
        Canvas { context, size in
            // 绘制背景
            context.fill(
                Path(CGRect(origin: .zero, size: size)),
                with: .color(.blue.opacity(0.2))
            )
            
            // 绘制一个圆形
            let circleRect = CGRect(x: size.width / 4, y: size.height / 4, width: size.width / 2, height: size.height / 2)
            context.stroke(Path(ellipseIn: circleRect), with: .color(.red), lineWidth: 5)
            
            // 绘制一条对角线
            let linePath = Path { path in
                path.move(to: CGPoint(x: 0, y: 0))
                path.addLine(to: CGPoint(x: size.width, y: size.height))
            }
            context.stroke(linePath, with: .color(.green), lineWidth: 3)
        }
        .frame(width: 300, height: 300)
    }
}

2、动态内容示例

Canvas 可以通过绑定或动画来绘制动态内容,例如一个旋转的圆环。

struct ContentView: View {
    @State private var rotation: Double = 0.0

    var body: some View {
        TimelineView(.animation) { timeline in
            let date = timeline.date.timeIntervalSinceReferenceDate
            let rotation = date.truncatingRemainder(dividingBy: 2) * 180
            
            Canvas { context, size in
                let radius = min(size.width, size.height) / 2 - 20
                let center = CGPoint(x: size.width / 2, y: size.height / 2)
                
                let startAngle = Angle(degrees: rotation)
                let endAngle = Angle(degrees: rotation + 270)
                
                var path = Path()
                path.addArc(center: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: false)
                
                context.stroke(path, with: .color(.orange), lineWidth: 10)
            }
        }
        .frame(width: 300, height: 300)
    }
}

值得注意的是,Canvas 的绘制内容是基于一次性的静态上下文执行的,并不会动态监听状态更新。为了解决这个问题,代码中需要明确地触发视图的更新,因此使用TimelineView视图,使得视图每次刷新时 Canvas 都重新计算绘制内容。

3、使用 TimelineView 创建动态时钟

TimelineView 提供了基于时间的更新机制,可以与 Canvas 配合实现动态时钟。

import SwiftUI

struct ClockView: View {
    var body: some View {
        TimelineView(.animation) { timeline in
            Canvas { context, size in
                let now = timeline.date
                let calendar = Calendar.current
                let second = Double(calendar.component(.second, from: now))
                let minute = Double(calendar.component(.minute, from: now))
                let hour = Double(calendar.component(.hour, from: now) % 12)
                
                let center = CGPoint(x: size.width / 2, y: size.height / 2)
                let radius = min(size.width, size.height) / 2 - 20
                
                // 秒针
                let secondAngle = Angle.degrees((second / 60) * 360 - 90)
                let secondEnd = CGPoint(
                    x: center.x + cos(Double(secondAngle.radians)) * radius,
                    y: center.y + sin(Double(secondAngle.radians)) * radius
                )
                context.stroke(
                    Path { path in
                        path.move(to: center)
                        path.addLine(to: secondEnd)
                    },
                    with: .color(.red), lineWidth: 2
                )
                
                // 其他指针可以类似绘制...
            }
        }
        .frame(width: 300, height: 300)
    }
}

优势与适用场景

1、动画和动态内容

与 SwiftUI 的动画系统结合良好,适合创建动态效果。

2、自定义绘图

如果需要绘制自定义图形、仪表盘、进度条等,Canvas 是理想选择。

3、高性能绘图

底层使用 Metal 支持,性能优异,适合实时更新的内容。

总结

Canvas 是 SwiftUI 中用于自定义绘图的现代工具,提供了高效、直观的绘图方式,支持动画和时间驱动的内容。无论是绘制静态图形还是动态内容,都可以很好地满足需求。

相关文章

1、SwiftUI实时更新内容的TimelineView视图:https://fangjunyu.com/2024/12/14/swiftui%e5%ae%9e%e6%97%b6%e6%9b%b4%e6%96%b0%e5%86%85%e5%ae%b9%e7%9a%84timelineview%e8%a7%86%e5%9b%be/

2、Apple图像渲染和计算框架Metal:https://fangjunyu.com/2024/11/17/apple%e5%9b%be%e5%83%8f%e6%b8%b2%e6%9f%93%e5%92%8c%e8%ae%a1%e7%ae%97%e6%a1%86%e6%9e%b6metal/

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注