Home > Net >  Random modify state after animation completion
Random modify state after animation completion

Time:12-16

I'd like to be able to change the state of a variable once an animation is complete and then redraw using the new value.

For example, in the code below, I'd like the Text to rotate a different amount each time the animation cycle completes.

struct RotateView: View {
    @State var angle: CGFloat = 0
    var body: some View {
        Text("Rotate")
            .rotationEffect(Angle.degrees(angle))
            .onAppear {
                withAnimation(.easeInOut(duration: 2).repeatForever()) {
                    self.angle = CGFloat.random(in: -360 ... 360)
                }
            }
    }
}

struct RotateView_Previews: PreviewProvider {
    static var previews: some View {
        RotateView()
    }
}

I understand that within the withAnimation body closure that I'm only setting the state to animate between and this is only executed once - thus, a random amount is calculated and the text rotates that amount forever.

I've looked at this excellent post that adds an onAnimationCompleted but it seems like overkill for my problem. In addition, while it sort of worked, the callback was called many times after each animation completed and randomly set the variable many times - causing the Text to rotate very quickly until the animation kicked off again?

CodePudding user response:

if you can stick to the defined duration of 2 secs, you can combine the .onAppear animation with additional animations kicked off by a timer that fires every two seconds.

    let timer = Timer.publish(every: 2, on: .main, in: .common).autoconnect()
    
    @State var angle: CGFloat = 0
    
    var body: some View {
        Text("Rotate")
            .rotationEffect(Angle.degrees(angle))
            .onAppear {
                withAnimation(.easeInOut(duration: 2)) {
                    self.angle = CGFloat.random(in: -360 ... 360)
                }
            }
            .onReceive(timer) { time in
                withAnimation(.easeInOut(duration: 2)) {
                    self.angle = CGFloat.random(in: -360 ... 360)
                }
            }
    }
  • Related