I'm dealing with rotation animation. I want:
when the button is clicked, the Shuriken will rotate continuously
When you click the button again, the Shuriken will rotate slowly and then stop But I'm having a problem, when Shuriken rotates slowly, the effect is stalling/jerking, not smooth.
ContentView:
struct ContentView: View {
@StateObject var viewModel = IntroductionViewModel()
var foreverAnimation: Animation { Animation.linear.speed(Double(viewModel.currentSpeed)).repeatForever(autoreverses: false)
}
var stopAnimation: Animation {
Animation.linear(duration: 3).speed(Double(viewModel.currentSpeed))
}
var body: some View {
VStack(spacing: 100) {
Image("shuriken")
.resizable()
.frame(width: 250, height: 250)
.rotationEffect(.degrees(viewModel.isRotated ? 360 : 0))
.animation(viewModel.isRotated ? foreverAnimation : stopAnimation)
Button {
viewModel.isRotated.toggle()
viewModel.isRotated ? viewModel.runFan() : viewModel.stopFan()
} label: {
Text("Rotate")
.foregroundColor(.white)
.padding()
.background(Color.blue)
.cornerRadius(10)
}
}
.padding()
}
}
- ViewModel:
class IntroductionViewModel: ObservableObject {
@Published var isRotated = false
@Published var currentSpeed: Float = Speed.five.getSpeed()
private var timer: Timer?
private func stopTimer() {
timer?.invalidate()
timer = nil
}
private func updateSpeedAnimation(_ speed: Float) {
if speed == 0 {
currentSpeed = 0
}
currentSpeed = speed
}
func runFan() {
stopTimer()
currentSpeed = Speed.five.getSpeed()
}
func stopFan() {
if currentSpeed == 0 {
updateSpeedAnimation(0)
}
let totalDuration: Float = 3
let decrement = currentSpeed / (totalDuration * 30)
timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true, block: { [weak self] _ in
guard let self = self else { return }
if self.currentSpeed <= decrement {
self.updateSpeedAnimation(0)
self.stopTimer()
} else {
self.updateSpeedAnimation(self.currentSpeed)
}
self.currentSpeed -= decrement
})
}
enum Speed: String, CaseIterable {
case off = "0"
case one = "1"
case two = "2"
case three = "3"
case four = "4"
case five = "5"
func getSpeed() -> Float {
switch self {
case .off:
return 0
case .one:
return 0.1
case .two:
return 0.2
case .three:
return 0.3
case .four:
return 0.4
case .five:
return 0.5
}
}
}
}
Pls help me how to fix it