将动画添加到ForEach循环元素(SwiftUI)

时间:2019-08-20 00:34:45

标签: swift swiftui

当ForEach循环的元素出现或消失时,有什么方法可以添加动画吗?

我尝试了多种方式使用withAnimation {}和.animation(),但它们似乎没有用

以下是一些代码(Xcode 11 beta 5):

import SwiftUI

struct test: View {
    @State var ContentArray = ["A","B","C"]
    var body: some View {
        ScrollView{
        VStack{
            ForEach(ContentArray.indices, id: \.self){index in
                ZStack{
                // Object
                    Text(self.ContentArray[index])
                    .frame(width:100,height:100)
                    .background(Color.gray)
                    .cornerRadius(20)
                    .padding()
                //Delete button
                    Button(action: {
                      self.ContentArray.remove(at: index)
                    }){
                    Text("✕")
                    .foregroundColor(.white)
                    .frame(width:40,height:40)
                    .background(Color.red)
                    .cornerRadius(100)
                   }.offset(x:40,y:-40)
             }
           }
         }   
       }
   }
}


#if DEBUG
struct test_Previews: PreviewProvider {
    static var previews: some View {
        test()
    }
}
#endif

从下面可以看出,没有动画,一切都会变得异常突然。任何解决方案都值得赞赏

重要提示:布局应该以元素数量更改时List所做的相同方式更改。例如,删除顶部对象后,每个对象都会自动移到顶部

Expected result

Bad result

1 个答案:

答案 0 :(得分:2)

该问题似乎仍然存在(Xcode 11.4),因为仅复制粘贴即可观察到相同的效果。因此,这里存在两个问题:首先,它需要正确设置动画和过渡的结合;其次,ForEach容器必须知道确切删除了哪个项目,因此必须标识项目,而不是匿名的索引。

因此,我们具有以下效果(转换/动画可以是其他效果):

demo

struct TestAnimationInStack: View {
    @State var ContentArray = ["A","B","C", "D", "E", "F", "G", "I", "J"]
    var body: some View {
        ScrollView{
        VStack{
            ForEach(Array(ContentArray.enumerated()), id: \.element){ (i, item) in // << 1) !
                ZStack{
                // Object
                    Text(item)
                    .frame(width:100,height:100)
                    .background(Color.gray)
                    .cornerRadius(20)
                    .padding()
                //Delete button
                    Button(action: {
                       withAnimation { () -> () in              // << 2) !!
                           self.ContentArray.remove(at: i)         
                       }
                    }){
                    Text("✕")
                    .foregroundColor(.white)
                    .frame(width:40,height:40)
                    .background(Color.red)
                    .cornerRadius(100)
                   }.offset(x:40,y:-40)
                }.transition(AnyTransition.scale)              // << 3) !!!
           }
         }
       }
   }
}