SwiftUI 动态添加子视图但动画不起作用

jus*_*nny 4 iphone ios swift swift5 swiftui

我想在 SwiftUI 中创建一个视图,动态添加一个带有动画的子视图。

struct ContentView : View {
    @State private var isButtonVisible = false

    var body: some View {
        VStack {
            Toggle(isOn: $isButtonVisible.animation()) {
                Text("add view button")
            }

           if isButtonVisible {
                 AnyView(DetailView())
                      .transition(.move(edge: .trailing))
                      .animation(Animation.linear(duration: 2))
             }else{
                    AnyView(Text("test"))
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码可以很好地处理动画。但是,当我将视图选择部分移动到函数中时,动画不再起作用(因为我想动态添加不同的视图,因此,我将逻辑放在一个函数中。)


struct ContentView : View {
    @State private var isButtonVisible = false
    var body: some View {
        VStack {
            Toggle(isOn: $isButtonVisible.animation()) {
                Text("add view button")
            }

            subView().transition(.move(edge: .trailing))
                     .animation(Animation.linear(duration: 2))   
    }

     func subView() -> some View {
         if isButtonVisible {
             return AnyView(DetailView())
         }else{
            return AnyView(Text("test"))
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对我来说看起来完全一样,但是,我不明白为什么它们会有不同的结果。有人可以解释我为什么吗?以及任何更好的解决方案?多谢!

Joh*_* M. 6

这是您的代码,已修改以使其正常工作:

struct ContentView : View {
    @State private var isButtonVisible = false

    var body: some View {
        VStack {
            Toggle(isOn: $isButtonVisible.animation()) {
                Text("add view button")
            }

            subView()
                .transition(.move(edge: .trailing))
                .animation(Animation.linear(duration: 2))
        }
    }

    func subView() -> some View {
        Group {
            if isButtonVisible {
                DetailView()
            } else {
                Text("test")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意两点:

  1. 你上面的两个例子是不同的,这就是为什么你得到不同的结果。第一个将过渡和动画应用于 DetailView,然后使用 AnyView 对其进行类型擦除。第二种类型 - 使用 AnyView 擦除 DetailView,然后应用过渡和动画。
  2. 与其使用 AnyView 和类型擦除,我更喜欢将条件逻辑封装在Group视图中。然后您返回的类型是Group,它将正确地设置动画。
  3. 如果您想在子视图的两种可能性上使用不同的动画,您现在可以将它们直接应用于DetailView()Text("test")

更新

Group方法将只与工作ifelseifelse语句。如果要使用开关,则必须将每个分支包装在AnyView(). 但是,这会破坏过渡/动画。目前无法使用switch 设置自定义动画。