Picker中的动画更改将多次运行动画

时间:2020-02-10 14:17:18

标签: swiftui

我有以下代码:

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

如果您从John切换到Betty(即在当前片段旁边选择一个片段),动画将运行一次,这正是我想要的。但是,如果您从John切换到Fred,则动画将运行多次,因为选择实际上并没有从0移到2,而是插值了之间的每一步。

如何限制动画仅运行一次?

1 个答案:

答案 0 :(得分:2)

如我所见,它需要将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()
    }
}