AnimatableArc 是一个自定义的 SwiftUI Shape,用于绘制弧形,并且支持通过动画动态改变弧形的起始角度和结束角度。
它的核心是实现了 SwiftUI 的 Shape 协议,并通过 AnimatableData 属性,使得弧形的参数(如起始角度和结束角度)可以参与动画。
为什么需要 AnimatableArc?
在 SwiftUI 中,内置的 Path 支持静态的弧形绘制,但是它不支持对角度等参数进行动画。为了实现一个动态可变化的弧形(如进度圆环、动态指示器等),需要创建一个自定义的 Shape。
AnimatableArc 通过实现 Shape 和 AnimatableData 的协议,将弧形的变化参数与 SwiftUI 的动画系统结合,轻松实现弧形的动态变化。
AnimatableArc 的核心代码
以下是 AnimatableArc 的基本实现:
import SwiftUI
struct AnimatableArc: Shape {
// 起始角度和结束角度
var startAngle: Angle
var endAngle: Angle
// 使弧形支持动画,利用 AnimatablePair 合并两个角度的动画数据
var animatableData: AnimatablePair<Double, Double> {
get { AnimatablePair(startAngle.radians, endAngle.radians) }
set {
startAngle = .radians(newValue.first)
endAngle = .radians(newValue.second)
}
}
// 定义绘制路径的方法
func path(in rect: CGRect) -> Path {
var path = Path()
let center = CGPoint(x: rect.midX, y: rect.midY) // 圆心
let radius = min(rect.width, rect.height) / 2 // 半径
path.addArc(center: center,
radius: radius,
startAngle: startAngle,
endAngle: endAngle,
clockwise: false) // 逆时针绘制
return path
}
}
代码解析
1、startAngle 和 endAngle
定义弧形的起始角度和结束角度。
使用 Angle 类型,以更直观的方式管理角度(.degrees 或 .radians)。
2、animatableData
实现 Shape 协议中的 animatableData,这是 SwiftUI 动画系统监控形状变化的关键。
使用 AnimatablePair 将两个角度(startAngle 和 endAngle)组合成动画数据。
动画期间,SwiftUI 会平滑地更新 animatableData 的值。
3、path(in:)
定义弧形的绘制逻辑。
使用 addArc 方法,根据 startAngle 和 endAngle 绘制弧形。
如何使用 AnimatableArc?
以下是一个简单的使用示例:
struct ContentView: View {
@State private var progress: Double = 0.0
var body: some View {
VStack {
// 使用 AnimatableArc 绘制弧形
AnimatableArc(startAngle: .degrees(0), endAngle: .degrees(360 * progress))
.stroke(Color.blue, lineWidth: 5) // 描边弧形
.frame(width: 200, height: 200) // 设置大小
.onTapGesture {
// 点击时触发动画
withAnimation(.linear(duration: 1)) {
progress = progress == 1.0 ? 0.0 : 1.0
}
}
Slider(value: $progress)
.padding()
}
}
}
代码运行效果
1、AnimatableArc 将根据 progress 的值动态绘制弧形。
2、点击弧形时,progress 在 0 和 1 之间切换,并通过动画平滑地改变弧形的结束角度。
3、Slider 允许用户手动控制 progress,实时更新弧形。
AnimatableArc 的典型用例
1、进度环:
使用弧形绘制一个完整的圆环,并通过动画显示进度。
2、动态指示器:
实现一个旋转的加载指示器,结合旋转效果。
3、自定义图形:
将 AnimatableArc 与其他图形组合,创建复杂的动态效果。
扩展 AnimatableArc
可以进一步扩展 AnimatableArc,比如添加弧形的颜色渐变、弧宽动画等:
动态弧宽示例:
struct DynamicArc: Shape {
var startAngle: Angle
var endAngle: Angle
var lineWidth: CGFloat
var animatableData: AnimatablePair<AnimatablePair<Double, Double>, CGFloat> {
get { AnimatablePair(AnimatablePair(startAngle.radians, endAngle.radians), lineWidth) }
set {
startAngle = .radians(newValue.first.first)
endAngle = .radians(newValue.first.second)
lineWidth = newValue.second
}
}
func path(in rect: CGRect) -> Path {
var path = Path()
let center = CGPoint(x: rect.midX, y: rect.midY)
let radius = (min(rect.width, rect.height) - lineWidth) / 2
path.addArc(center: center,
radius: radius,
startAngle: startAngle,
endAngle: endAngle,
clockwise: false)
return path
}
}
使用示例:
struct ContentView: View {
@State private var progress: Double = 0.01
@State private var arcWidth: CGFloat = 5.0
var body: some View {
VStack {
DynamicArc(startAngle: .degrees(0), endAngle: .degrees(360 * progress), lineWidth: arcWidth)
.stroke(Color.red, lineWidth: arcWidth)
.frame(width: 200, height: 200)
.onTapGesture {
withAnimation(.easeInOut(duration: 1)) {
progress = progress == 1.0 ? 0.01 : 1.0
arcWidth = arcWidth == 5.0 ? 15.0 : 5.0
}
}
}
}
}
总结
AnimatableArc 是一个强大的工具,用于绘制和动画化弧形。
它通过 Shape 和 AnimatableData 实现与 SwiftUI 动画系统的无缝集成。
可以扩展用于各种动态效果,增强界面的交互性和表现力。
相关文章
SwiftUI动画数据类型AnimatableData和AnimatablePair:https://fangjunyu.com/2024/12/16/swiftui%e5%8a%a8%e7%94%bb%e6%95%b0%e6%8d%ae%e7%b1%bb%e5%9e%8banimatabledata%e5%92%8canimatablepair/