Home > Software engineering >  SwiftUI Animation Speed Modifier for Rotation Not Changing from the View
SwiftUI Animation Speed Modifier for Rotation Not Changing from the View

Time:01-17

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 }
            }
        }
        
    }
}
  • Related