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/