Остановить анимацию swiftUI и перейти к значению назначения - PullRequest
1 голос
/ 23 марта 2020

Я анимирую оставшееся время для некоторых сцен в моем приложении. У меня проблема в том, что когда пользователь прерывает эту сцену, переходя к следующей сцене, анимация не останавливается

Этот код является упрощенной версией происходящего:

struct ContentView: View {
    @State private var remaining: Int = 40
    @State private var sceneIndex: Int = 0

    var body: some View {
        VStack(spacing: 30) {
            Text("Remaining:")
            EmptyView().modifier(DoubleModifier(value: remaining))

            Button(action: {
                self.sceneIndex += 1
                if self.sceneIndex == 1 {
                    withAnimation(.linear(duration: 10)) {
                        self.remaining = 30
                    }
                } else {
                    withAnimation(.linear(duration: 0)) {
                        self.remaining = 30 // changing this to any other value will stop the animation
                    }
                }
            }) {
                Text("Go to next scene")
            }
        }
    }
}
struct DoubleModifier: AnimatableModifier {
    private var value: Double

    init(value: Int) {
        self.value = Double(value)
    }

    var animatableData: Double {
        get { value }
        set { value = newValue }
    }

    func body(content: Content) -> some View {
        Text("\(Int(value)) seconds remaining")
    }
}

То, что происходит, - то, что, когда пользователь щелкает, анимация обратного отсчета инициализируется с продолжительностью 10 секунд и устанавливает оставшееся время от 40 до 30 секунд. Теперь, когда пользователь нажимает кнопку пропуска, анимация должна остановиться и go до оставшихся 30 секунд. Тем не менее, он по-прежнему показывает анимацию от 40 до 30 (где-то посередине).

Если я изменю self.remaining на 30 в операторе else, значение не обновляется, поскольку оно уже установлено на 30, но внутренне это все еще оживляет. Если я изменю self.remaining на любое другое допустимое значение, кроме 30, например self.remaining = 29, анимация действительно немедленно остановится.

Я мог бы заменить содержимое в выражении else на:

withAnimation(.linear(duration: 0)) {
   self.remaining = 29

   DispatchQueue.main.async {
       self.remaining = 30
   }
}

, который работает, но чувствует себя очень грязно, и в моем случае не всегда возможно использовать DispatchQueue.main.asyn c

Есть ли другой, лучший способ остановить анимацию и пропустить к месту назначения?

Возможно ли каким-то образом присвоить некоторый идентификатор идентификатору self.remaining = 30 в операторе else так, чтобы swiftUI знал, что значение действительно изменилось, хотя на самом деле это не произошло, так что swiftUI останавливает анимацию

1 Ответ

0 голосов
/ 23 марта 2020

Не ясно, что такое логика c, запланированная шаг за шагом от сцены к сцене, но цель, как она постулируется, может быть достигнута с помощью следующего body:

var body: some View {
    VStack(spacing: 30) {
        Text("Remaining:")
        EmptyView().modifier(DoubleModifier(value: remaining)).id(sceneIndex)

        Button(action: {
            self.sceneIndex += 1
            withAnimation(.linear(duration: 10)) {
                self.remaining = 30
            }
        }) {
            Text("Go to next scene")
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...