0

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

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)
            }
        }
    }
}

我希望 Text("Hide") 将为父 VStack 内的位置设置动画。但它会坚持到最后一个位置并从那里淡出并动画回到那个位置。有没有可能给这个动画一个更自然的感觉,所以它会在它的父级内部动画。

这是一个可视化问题的 gif: 在此处输入图像描述

4

1 回答 1

0

问题是这Bar是一个新的View,因此只是淡出或出现在它的最终目的地,所以它的位置没有动画,因为它以前不在屏幕上。

诀窍是始终保持Bar在屏幕上并调整其opacity. .offset用于防止视图因单词Bar并不总是存在而增长。添加或删除空白文本视图Text(" ")以使视图像以前一样增长。

这是提供更好看的动画的解决方法:

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之间设置动画的解决方案。Text("Bar").frame(height: 0)Text("Bar")

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)
            }
        }
    }
}

于 2020-10-12T18:09:45.427 回答