Animation SwiftUI VStack动画看起来已损坏-动画视图不会更改位置

Animation SwiftUI VStack动画看起来已损坏-动画视图不会更改位置,animation,swiftui,vstack,Animation,Swiftui,Vstack,让我们看一下以下代码片段: struct ContentView: View { @State private var isViewHidden: Bool = false let data = [1,2,3,4,5,6,7] public var body: some View { VStack { Button("Hide", action: { withAnimation {

让我们看一下以下代码片段:

struct ContentView: View {
    @State private var isViewHidden: Bool = false
    let data = [1,2,3,4,5,6,7]
    public var body: some View {
        VStack {
            Button("Hide", action: {
                withAnimation {
                    isViewHidden.toggle()
                }
            })
            ForEach(data, id: \.self) { _ in
                VStack {
                    Text("Foo")
                    if isViewHidden {
                        Text("Bar").animation(nil)
                    }
                }.padding().background(Color.green)
            }
        }
    }
}
我希望文本(“隐藏”)将为父VStack中的位置设置动画。 但它将坚持到最后一个位置,然后从那里淡出,并将动画恢复到该位置。有没有可能给这个动画一个更自然的感觉,这样它将在其父动画

下面是一个gif,可以直观地显示问题:

问题在于
栏是一个新的
视图
,因此只会淡出或出现在其最终目的地,因此其位置不会动画,因为它以前不在屏幕上

诀窍是始终保持
在屏幕上,只需调整其
不透明度
.offset
用于防止视图因并非始终存在的单词
条而增长。添加或删除一个空白文本视图
文本(“”
),以使视图像以前一样增长

以下是一个解决方案,它提供了一个外观更好的动画:

struct ContentView: View {
    @State private var isViewHidden: Bool = false
    let data = [1,2,3,4,5,6,7]
    public var body: some View {
        VStack {
            Button("Hide", action: {
                withAnimation {
                    isViewHidden.toggle()
                }
            })
            ForEach(data, id: \.self) { _ in
                VStack {
                    ZStack {
                        Text("Foo")
                        Text("Bar")
                            .offset(y: 28)
                            .opacity(isViewHidden ? 0 : 1)
                    }
                    if !isViewHidden {
                        Text(" ")
                    }

                }.padding().background(Color.green)
            }
        }
    }
}

在这里,它在模拟器中运行:


解决方案2:使用
.matchedGeometryEffect

这里有一个解决方案,它使用
.matchedGeometryEffect
文本(“条”).frame(高度:0)
文本(“条”)
之间设置动画


事实上我无法想象你期望什么。。。它会按要求进行动画制作。SwiftUI容器与内容紧密相连,反之亦然。。。加上“隐藏”的默认不透明度转换。。。一瞬间加上所有单元格。难道你看不到视图在动画期间是如何移出其容器的吗?要隐藏的视图的Y值越大,视图移动的次数就越多。使用
.matchedGeometryEffect
,我添加了一个替代解决方案。看看吧。谢谢你在这方面做了更多的工作。我接受了这一回答,但老实说,这对我来说似乎还是有点骇人听闻。
struct ContentView: View {
    @Namespace var namespace
    @State private var isViewHidden: Bool = false
    let data = [1,2,3,4,5,6,7]
    public var body: some View {
        VStack {
            Button("Hide") {
                withAnimation {
                    isViewHidden.toggle()
                }
            }
            ForEach(data, id: \.self) { id in
                VStack {
                    Text("Foo")
                    if isViewHidden {
                        Text("Bar").frame(height: 0)
                            .matchedGeometryEffect(id: id, in: namespace)
                    } else {
                        Text("Bar")
                            .matchedGeometryEffect(id: id, in: namespace)
                    }
                }
                .padding().background(Color.green)
            }
        }
    }
}