随ForEach插入的SwiftUI视图不随动画更新

时间:2020-09-22 05:18:01

标签: swiftui swiftui-animation

我创建了一个简单的函数,该函数可以插入三个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会破坏动画。

1 个答案:

答案 0 :(得分:2)

为了使SwiftUI动画化按钮,它需要能够观察唯一标识的视图的渲染之间的变化。在第一种情况下,视图的ID为012。这样动画就可以了。

当您应用.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
}
相关问题