我创建了一个简单的函数,该函数可以插入三个Button。我希望单个按钮在按下时能够旋转。我最初的尝试是这样的:
ForEach(0..<3, id: \.self) { number in {
Button(action: {
self.flagTapped(number: index)
withAnimation(Animation.interpolatingSpring(stiffness: 15.0, damping: 3.0)) {
animationAmount2 += 360
}
}) {
Image(self.countries[index])
.renderingMode(.original)
}
.clipShape(Capsule())
.overlay(Capsule().stroke(Color.black, lineWidth: 1)
.shadow(color: .black, radius: 10, x: 3, y: 3)
.rotation3DEffect(
.degrees(animationAmount2),
axis: (x: 0.0, y: 1.0, z: 0.0),
anchor: .center,
anchorZ: 0.0,
perspective: 1.0
)
}
它可以工作,但是问题在于当您按下任何按钮时每个按钮都会动画,因为animationAmount2是@State属性,因此在更新时,每个按钮都会进行动画,而不仅仅是被按下的按钮。
我的下一个想法是创建一个自定义按钮,并在其中插入动画代码和属性,以使按钮可以单独进行动画处理。结果是:
func getFlagView(index: Int) -> some View {
let flag = CustomButton(country: countries[index], index: index) { (Index) in
flagTapped(number: index)
}
return flag
}
我现在在ForEach中调用此函数,它完美地插入了按钮,只有按下的按钮旋转。问题在于,刷新视图时,它永远不会重绘按钮。 ForEach正在执行,但是就像它只是忽略对getFlagView的调用一样。
在CustomButton调用的末尾添加.id(UUID())可以解决以下问题:
func getFlagView(index: Int) -> some View {
let flag = CustomButton(country: countries[index], index: index) { (Index) in
flagTapped(number: index)
}.id(UUID())
return flag
}
现在,当视图按预期刷新时,按钮会重新绘制,但是动画不起作用。我真的不知道为什么添加UUID会破坏动画。
答案 0 :(得分:2)
为了使SwiftUI动画化按钮,它需要能够观察唯一标识的视图的渲染之间的变化。在第一种情况下,视图的ID为0
,1
和2
。这样动画就可以了。
当您应用.id(UUID())
时,这会给按钮一个唯一的id
每次绘制。因此,SwiftUI不会看到您已更改按钮,因为每次执行ForEach
时,它总是将3个按钮视为3个全新按钮。
您需要一个id
来唯一地标识每个按钮,但是直到国家/地区更改后它才会更改。您需要一个id
来唯一标识每个国家/地区,并且id
是该国家/地区的名称。
更改您的getFlagView
,以使用国家/地区名称作为id
:
func getFlagView(index: Int) -> some View {
let flag = CustomButton(country: countries[index], index: index) { (Index) in
flagTapped(number: index)
}.id(countries[index])
return flag
}