SwiftUI自定义弧形的AnimatableArc
SwiftUI自定义弧形的AnimatableArc

SwiftUI自定义弧形的AnimatableArc

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/

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

发表回复

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