使用SwiftUI,我如何为饼形进度条添加动画效果?

4

我已经编写好了显示饼图进度条的代码。我需要为这个进度条添加动画效果。我尝试使用线性动画,但并没有帮助。我现在卡住了,不知道如何让它动起来。有人可以帮忙吗?以下是代码:

import SwiftUI

struct PieProgress: View {
    @State var progress: Float

    var body: some View {
        GeometryReader { geometry in
            VStack(spacing:20) {
                HStack{
                    Text("0%")
                    Slider(value: self.$progress)
                    Text("100%")
                }.padding()
                Circle()
                    .stroke(Color.gray, lineWidth: 1)
                    .frame(width: geometry.size.width, height: geometry.size.width, alignment: .center)
                    .padding()
                    .overlay(
                        PieShape(progress: Double(self.progress))
                            .frame(width: geometry.size.width - 10, height: geometry.size.width - 10 , alignment: .center)
                            .foregroundColor(.blue)
                    )
            }
        }
    }
}

struct PieShape: Shape {
    var progress: Double = 0.0
    private let startAngle: Double = (Double.pi) * 1.5
    private var endAngle: Double {
        get {
            return self.startAngle + Double.pi * 2 * self.progress
        }
    }

    func path(in rect: CGRect) -> Path {
        var path = Path()
        let arcCenter =  CGPoint(x: rect.size.width / 2, y: rect.size.width / 2)
        let radius = rect.size.width / 2
        path.move(to: arcCenter)
        path.addArc(center: arcCenter, radius: radius, startAngle: Angle(radians: startAngle), endAngle: Angle(radians: endAngle), clockwise: false)
        path.closeSubpath()
        return path
    }
}
1个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
3

Xcode 13.4 / iOS 15.5

使用更新的弃用方法,现在不再有硬编码。

demo

Circle()
    .stroke(Color.gray, lineWidth: 1)
    .overlay(
        PieShape(progress: Double(self.progress))
            .padding(4)
            .foregroundColor(.blue)
    )
    .frame(maxWidth: .infinity)
    .animation(Animation.linear, value: progress) // << here !!
    .aspectRatio(contentMode: .fit)

测试代码在这里

原文

这是一种可能的方法(已经测试并且适用于Xcode 11.2 / iOS 13.2):

  1. 您需要为您的形状指定 animatableData,如下所示:

    struct PieShape: Shape { var progress: Double = 0.0

     var animatableData: Double {
         get {
             self.progress
         }
         set {
             self.progress = newValue
         }
     }
     ...
    
  2. 然后将动画添加到 Circle 中:

    Circle() .stroke(Color.gray, lineWidth: 1) .frame(width: geometry.size.width, height: geometry.size.width, alignment: .center) .padding() .overlay( PieShape(progress: Double(self.progress)) .frame(width: geometry.size.width - 10, height: geometry.size.width - 10 , alignment: .center) .foregroundColor(.blue) ) .animation(Animation.linear) // << 这里要加上!!

就是这样。为了测试(仅限测试!),您可以在PieProgress中添加以下内容

.onAppear {
    DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
        self.progress = 0.72
    }
}
注意:将 PieProgress 用作可重用组件时,最好将 progress 设为@Binding,以防万一。

我已将其更改为@Binding。谢谢。 - Felix Marianayagam
但是你在哪里使用这个可动画数据? - Vivienne Fosh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,