Анимированные изменения в Picker будут запускать анимацию несколько раз - PullRequest
1 голос
/ 10 февраля 2020

У меня есть следующий код:

import SwiftUI

let names = ["John", "Betty", "Fred", "May", "Judy"]

struct ContentView: View {
    @State var selection = 0

    var body: some View {
        VStack(spacing: 20) {
            Picker("Name", selection: self.$selection.animation(.linear(duration: 0.3))) {
                ForEach(names.indices, id: \.self) { i in
                    Text(names[i]).tag(i)
                }
            }.pickerStyle(SegmentedPickerStyle())
            Text(names[self.selection])
                .font(.title)
                .fixedSize()
                .modifier(MyShake(animatableData: CGFloat(self.selection)))
        }
        .padding()
    }
}

struct MyShake: GeometryEffect {
    var animatableData: CGFloat

    func modifier(_ x: CGFloat) -> CGFloat {
        10 * sin(x * .pi * 2)
    }

    func effectValue(size: CGSize) -> ProjectionTransform {
        let transform1 = ProjectionTransform(CGAffineTransform(translationX: 10 + modifier(animatableData), y: 0))
        return transform1
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
        .previewDevice("iPhone SE")
    }
}

Если вы переключитесь с Джона на Бетти (то есть выберите сегмент рядом с текущим), анимация запустится один раз, и это именно то, что я хочу. Однако если вы переключитесь с Джона на Фреда, анимация будет выполняться несколько раз, потому что выделение фактически не перемещается от 0 до 2, а интерполирует каждый шаг между ними.

Как можно ограничить анимацию так, чтобы он запускается только один раз?

1 Ответ

2 голосов
/ 10 февраля 2020

Как я вижу, необходимо преобразовать selection в toggle. Пожалуйста, найдите ниже возможный подход для этого. Протестировано и работает с Xcode 11.2 / iOS 13.2

Демо:

enter image description here

Изменения только в ContentView:

struct ContentView: View {
    @State var selection = 0
    @State var shaking = false
    var body: some View {
        let value = Binding<Int>(
            get: { self.selection },
            set: { newValue in
                withAnimation(Animation.linear(duration: 0.3)) {
                    self.shaking.toggle()
                }
                self.selection = newValue
            })
        return VStack(spacing: 20) {
            Picker("Name", selection: value) {
                ForEach(names.indices, id: \.self) { i in
                    Text(names[i]).tag(i)
                }
            }.pickerStyle(SegmentedPickerStyle())
            Text(names[self.selection])
                .font(.title)
                .fixedSize()
                .modifier(MyShake(animatableData: CGFloat(self.shaking ? 1 : 0)))
        }
        .padding()
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...