I have been trying to change the rotation animation speed of the fan dynamically from SwiftUI code. But once the animation has been started, it seems that onChange it is not possible to change it to operate at different speed i.e not possible to modify .speed modifier. The idea is that animation speed changes when the speed variable changes.
Any ideas how to make this work?
struct FanTest: View {
@State var rotationAngle : Double = 0.0
@State var speed : Int = 0
var body: some View {
HStack {
Image(systemName: "fanblades")
.rotationEffect(.degrees(rotationAngle))
Text("\(speed)")
}
.scaleEffect(4)
.onAppear {
Timer.scheduledTimer(withTimeInterval: 5, repeats: true, block: { Timer in
speed = 1
if speed > 2 { speed = 0 }
})
}
.onChange(of: speed) { _ in
if speed == 0 {
withAnimation(.linear(duration: 1).speed(1).repeatForever(autoreverses: false))
{ rotationAngle = 360.0 }
}
if speed == 1 {
withAnimation(.linear(duration: 1).speed(2).repeatForever(autoreverses: false))
{ rotationAngle = 360.0 }
}
if speed == 2 {
withAnimation(.linear(duration: 1).speed(3).repeatForever(autoreverses: false))
{ rotationAngle = 360.0 }
}
}
}
}
CodePudding user response:
Your fan already has an animation and the rotation angle has already been changed to 360
. You need to remove the existing animation before applying a new one.
One simple way to accomplish this is to tell SwiftUI to replace the fan with a new View
that is not yet animating. This can be done by giving the fan an id
and changing the id
when you want a new fan speed. Also, reset the rotationAngle
back to 0
so that it will animate when set to 360
inside the withAnimation
block.
struct FanTest: View {
@State var rotationAngle : Double = 0.0
@State var speed : Int = 0
@State var fanID = UUID() // here
var body: some View {
HStack {
Image(systemName: "fanblades")
.id(fanID) // here
.rotationEffect(.degrees(rotationAngle))
Text("\(speed)")
}
.scaleEffect(4)
.onAppear {
Timer.scheduledTimer(withTimeInterval: 5, repeats: true, block: { timer in
speed = 1
if speed > 2 { speed = 0 }
})
}
.onChange(of: speed) { _ in
rotationAngle = 0 // here
fanID = UUID() // here
if speed == 0 {
withAnimation(.linear(duration: 1).speed(1).repeatForever(autoreverses: false))
{ rotationAngle = 360.0 }
}
if speed == 1 {
withAnimation(.linear(duration: 1).speed(2).repeatForever(autoreverses: false))
{ rotationAngle = 360.0 }
}
if speed == 2 {
withAnimation(.linear(duration: 1).speed(3).repeatForever(autoreverses: false))
{ rotationAngle = 360.0 }
}
}
}
}