在 SwiftUI 中呈现时,视图的不同元素的不同过渡

Different transitions for different elements of a view when it's presented in SwiftUI

所以当在 SwiftUI 中呈现视图时,我试图以不同的方式显示不同的元素(一个是从前缘滑入,另一个元素是幻灯片从屏幕底部向上)。我的基本视图结构如下:

struct ViewName: View {
  @ObservedObject var appState: AppState //this is just a class that tracks the state of app variables, in my case it holds a variable called 'showView' that indicates whether or not to show the view.
  var body: some View {
    ZStack {
      Color.white
        .edgesIgnoringSafeArea(.all)
      VStack {
        Text("Test")
      }.transition(AnyTransition.asymmetric(insertion: .move(edge: .leading), removal: .move(edge: .trailing)))
      VStack {
        Spacer()
        HStack {
          Text("Test2")
          Spacer()
          Text("Test3")
        }
      }.transition(AnyTransition.move(edge: .bottom))
    }
  }
}

在其他地方,我用类似的东西初始化了视图:

if appState.showView {
  ViewName(appState: appState)
}

以及一个用于更改是否显示视图的按钮:

Button(action: {
  withAnimation {
    appState.showView.toggle()
  }
}, label: { 
  Text("Click me") 
})

虽然 Swift 似乎不知道如何处理这两个过渡,但它有点将它们默认为淡入不透明过渡。不知道如何解决这个问题。非常感谢任何帮助!

问题是你只有1个if appState.showView {

if appState.showView {
    ViewName(appState: appState)
}

因此,SwiftUI 仅使用默认的淡入淡出过渡动画 整个 ViewName(因为您没有指定)。

相反,您需要在每个要设置动画的单独元素上使用 if appState.showView {

class AppState: ObservableObject {
    @Published var showView = false
}

struct ContentView: View {
    @StateObject var appState = AppState()
    var body: some View {
        VStack {
            Button(action: {
                withAnimation {
                    appState.showView.toggle()
                }
            }, label: {
                Text("Click me")
            })
            
            ViewName(appState: appState) /// just make this always showing
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.green)
    }
}

struct ViewName: View {
    @ObservedObject var appState: AppState
    var body: some View {
        ZStack {
            if appState.showView { /// need this, so `ViewName` will be invisible when `appState.showView` is false
                Color.white
                .edgesIgnoringSafeArea(.all)
                /// optional: add a transition here too
                /// by default, it will fade
            }
            
            if appState.showView { /// need this!
                VStack {
                    Text("Test")
                }
                .zIndex(1) /// needed for removal transition
                .transition(AnyTransition.asymmetric(insertion: .move(edge: .leading), removal: .move(edge: .trailing)))
            }
            
            if appState.showView { /// need this!
                VStack {
                    Spacer()
                    HStack {
                        Text("Test2")
                        Spacer()
                        Text("Test3")
                    }
                }
                .zIndex(2) /// needed for removal transition
                .transition(AnyTransition.move(edge: .bottom))
            }
        }
    }
}