SwiftUI - 动画过渡

SwiftUI - Animate transition

我在模式 sheet 上有一个注销按钮,可以让用户返回登录屏幕。为此,我首先关闭 sheet,然后使用 asyncAfter(deadline:) 设置一个环境变量,使登录页面出现。一切正常,但是一旦 sheet 被关闭,从 sheet 下的视图到登录页面的转换就非常不和谐。主要是因为没有。顶视图消失了,显示了登录视图。我知道我可以创建自定义转场,但我不知道将它附加到哪里。比如说,我想淡出 sheet 下面的视图。 (不过,我对任何类型的转变都持开放态度!)

这是引导流量的结构:

struct ConductorView: View {
   @EnvironmentObject var tower: Tower
   let onboardingCompleted = UserDefaults.standard.bool(forKey: "FirstVisit")
    
   var body: some View {
      VStack {
         if tower.currentPage == .onboarding {
            Onboarding1View()
         } else if tower.currentPage == .login {
            LoginView()
         } else if tower.currentPage == .idle {
            LoginView()
         }
      }.onAppear{
         if self.onboardingCompleted {
            self.tower.currentPage = .login
         } else {
            self.tower.currentPage = .onboarding
         }
      }
   }
}

这是 sheet 上的退出按钮:

Button(action: {
   self.presentationMode.wrappedValue.dismiss()
   DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
      self.tower.currentPage = .login
   }
}) {
   Text("Sign Out")
}

这是您复制的代码的简化演示(我做了一些更长的延迟以使其模式可见)。当然,您需要通过更改过渡类型或动画等来根据需要调整它。使用 Xcode 12 / iOS 14

进行测试

class Tower: ObservableObject {
    enum PageType {
        case onboarding, login, idle
    }
    @Published var currentPage: PageType = .onboarding
}

struct ConductorView: View {
   @EnvironmentObject var tower: Tower
   let onboardingCompleted = false

   var body: some View {
      VStack {
         if tower.currentPage == .onboarding {
            Onboarding1View()
         } else if tower.currentPage == .login {
            Text("LoginView")
                .transition(.move(edge: .trailing))    // << here !!
         } else if tower.currentPage == .idle {
            Text("IdleView")
         }
      }
      .animation(.default, value: tower.currentPage)   // << here !!
      .onAppear{
         if self.onboardingCompleted {
            self.tower.currentPage = .login
         } else {
            self.tower.currentPage = .onboarding
         }
      }
   }
}


struct Onboarding1View: View {
   @EnvironmentObject var tower: Tower
    @Environment(\.presentationMode) var presentationMode
    @State private var isPresented = true
    var body: some View {
        Text("Login")
            .sheet(isPresented: $isPresented) {
                Button(action: {
                   self.presentationMode.wrappedValue.dismiss()
                   DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                      self.tower.currentPage = .login
                   }
                }) {
                   Text("Sign Out")
                }
            }
    }
}