SwiftUI Circle View 动画故障

SwiftUI Circle View animation glitch

import SwiftUI

struct CircularProgressView: View {
    
    @Binding var progress: Float
    private let strokeStyle = StrokeStyle(lineWidth: 30.0, lineCap: .round, lineJoin: .round)
    private let rotation = Angle(degrees: 270.0)
        
    var body: some View {
        ZStack {
            Circle()
                .trim(from: 0.0, to: CGFloat(min(self.progress, 1.0)))
                .stroke(style: strokeStyle)
                .opacity(0.2)
                .foregroundColor(Color.black)
                .rotationEffect(rotation)
                .offset(x: 0, y: 10)
                            
            Circle()
                .trim(from: 0.0, to: CGFloat(min(self.progress, 1.0)))
                .stroke(style: strokeStyle)
                .opacity(1)
                .foregroundColor(Color.white)
                .rotationEffect(rotation)
                
        }
        .animation(.linear(), value: progress)
    }
}

struct CircularProgressView_Previews: PreviewProvider {
    static var previews: some View {
        OtherView(progress: 0.6)
    }
    
    struct OtherView : View {
        
        @State var progress : Float = 0.0
        
        var body: some View {
            ZStack {
                Color.yellow
                VStack {
                    CircularProgressView(progress: self.$progress)
                        .padding(50)
                    Button(action: {
                        if(progress >= 1) {
                            progress = 0
                        } else {
                            progress += 0.1
                        }
                    }) {
                        Text("try me")
                            .frame(width: 200, height: 50)
                            .overlay(
                                RoundedRectangle(cornerRadius: 20)
                                    .stroke(Color.blue, lineWidth: 2)
                            )
                            .padding(.bottom, 100)
                            
                    }
                }
            }.ignoresSafeArea()
        }
    }
}

可能是什么原因?

确实不清楚,可能是由于未定义形状大小的缘故...无论如何,似乎使用绘图组解决了这个问题。

这是一个固定的代码。测试 Xcode 13 / iOS 15.

struct CircularProgressView: View {

    @Binding var progress: Float
    private let strokeStyle = StrokeStyle(lineWidth: 30.0, lineCap: .round, lineJoin: .round)
    private let rotation = Angle(degrees: 270.0)

    var body: some View {
        ZStack {
            Group {
                Circle()
                    .trim(from: 0.0, to: CGFloat(min(self.progress, 1.0)))
                    .stroke(style: strokeStyle)
                    .opacity(0.2)
                    .foregroundColor(Color.black)
                    .rotationEffect(rotation)
                    .offset(x: 0, y: 10)
                Circle()
                    .trim(from: 0.0, to: CGFloat(min(self.progress, 1.0)))
                    .stroke(style: strokeStyle)
                    .opacity(1)
                    .foregroundColor(Color.white)
                    .rotationEffect(rotation)
            }
            .padding()    // << compensate offset within own bounds
        }
        .drawingGroup()   // << here !!
        .animation(.linear, value: progress)
    }
}

struct CircularProgressView_Previews: PreviewProvider {
    static var previews: some View {
        OtherView(progress: 0.6)
    }

    struct OtherView : View {

        @State var progress : Float = 0.0

        var body: some View {
            ZStack {
                Color.yellow
                VStack {
                    CircularProgressView(progress: self.$progress)
                        .padding()
                    Button(action: {
                        if(progress >= 1) {
                            progress = 0
                        } else {
                            progress += 0.1
                        }
                    }) {
                        Text("try me")
                            .frame(width: 200, height: 50)
                            .overlay(
                                RoundedRectangle(cornerRadius: 20)
                                    .stroke(Color.blue, lineWidth: 2)
                            )
                            .padding(.bottom, 100)
                    }
                }
            }.ignoresSafeArea()
        }
    }
}

backup