0

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

enter image description here

Pls help me how to fix it

koen
  • 5,383
  • 7
  • 50
  • 89
finn
  • 1
  • 1

0 Answers0