我有以下代码:
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,而是插值了之间的每一步。
如何限制动画仅运行一次?
答案 0 :(得分:2)
如我所见,它需要将selection
转换为toggle
。请找到以下可能的方法。经过测试并与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()
}
}