SwiftUI圆线宽度更改停止修剪动画

时间:2020-10-06 14:35:42

标签: ios swift swiftui

我想为圆的修剪属性设置动画。但是,如果动画正在运行并且我更改了线宽,则动画会立即(且意外地)结束。

有人知道我在做什么错吗?我敢肯定这是一件非常简单的事情。

感谢您的回答!

enter image description here

import SwiftUI

struct ContentView: View {
    @State var progress: Double = 0.01
    @State var lineWidth: CGFloat = 20
    
    var body: some View {
        VStack{
            CircleView(progress: progress, lineWidth: lineWidth)
                .foregroundColor(.orange)
                .onAppear{
                    withAnimation(.linear(duration: 20)){
                        progress = 1
                    }
                }
                .padding()
            
            Button(action: {
                withAnimation{
                    lineWidth = 40
                }
                
            }, label: {Text("Change Line Width")})
        }
    }
}

struct CircleView: View {
    var progress: Double
    var lineWidth: CGFloat
    
    var body: some View {
        Circle()
            .trim(from: 0, to: CGFloat(progress))
            .stroke(style: StrokeStyle(lineWidth: lineWidth, lineCap: .round, lineJoin: .round))
            .padding()
    }
}

2 个答案:

答案 0 :(得分:1)

只需删除第二个动画就可以了。经过Xcode 12 / iOS 14的测试

demo

Button(action: {
   lineWidth = 40     // << no animation here !!
}, label: {Text("Change Line Width")})

答案 1 :(得分:1)

我不确定您可以直接完成您希望做的事情。该行的描边使用lineWidth,因此我认为您不能使用单独的时间间隔对其进行动画处理。

您可以做的是随着时间的推移更改lineWidth,以便在运行圆动画并重画圆时,它将使用新值。

牢记这一点,我创建了函数changeValueOverTime(value:newValue:duration)来做到这一点:

struct ContentView: View {
    @State var progress: Double = 0.01
    @State var lineWidth: CGFloat = 20
    
    var body: some View {
        VStack{
            CircleView(progress: progress, lineWidth: $lineWidth)
                .foregroundColor(.orange)
                .onAppear{
                    withAnimation(.linear(duration: 20)){
                        progress = 1
                    }
                }
                .padding()
            
            Button(action: {
                changeValueOverTime(value: $lineWidth, newValue: 40, duration: 0.5)
                
            }, label: {Text("Change Line Width")})
        }
    }
    
    func changeValueOverTime(value: Binding<CGFloat>, newValue: CGFloat, duration: Double) {
        
        let timeIncrements = 0.02
        let steps = Int(duration / timeIncrements)
        var count = 0
        let increment = (newValue -  value.wrappedValue) / CGFloat(steps)
        Timer.scheduledTimer(withTimeInterval: timeIncrements, repeats: true) { timer in
            value.wrappedValue += increment
            count += 1
            if count == steps {
                timer.invalidate()
            }
        }
    }
}