Swiftui 选择器中的动画更改将多次运行动画

Swiftui 选择器中的动画更改将多次运行动画,swiftui,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.anima

我有以下代码:

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,而是在其间对每一步进行插值


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

正如我看到的,它需要将
选择
转换为
切换
。请找出以下可能的方法。已测试并可与Xcode 11.2/iOS 13.2配合使用

演示:

更改仅在
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()
    }
}
struct ContentView:View{
@状态变量选择=0
@状态变量=false
var body:一些观点{
让值=绑定(
获取:{self.selection},
集合:{newValue in
带动画(动画.线性(持续时间:0.3)){
self.shacking.toggle()
}
self.selection=newValue
})
返回VStack(间距:20){
选择器(“名称”,选择:值){
ForEach(names.index,id:\.self){i in
文本(名称[i])。标记(i)
}
}.pickerStyle(SegmentedPickerStyle())
文本(名称[自选择])
.font(.title)
.fixedSize()
.modifier(MyShake(animatableData:CGFloat(self.shacking?1:0)))
}
.padding()
}
}

有趣的解决方案。自定义绑定可以将更改扩展到两个状态变量。然后,动画由bool状态变量驱动,而不是int状态变量。聪明。