SwiftUI - Transición animada
Tengo un botón de cierre de sesión en una hoja modal que lleva al usuario a la pantalla de inicio de sesión. Para lograr esto, primero descarto la hoja y luego, usando asyncAfter (fecha límite :) establezco una variable de entorno que hace que aparezca la página de inicio de sesión. Todo funciona bien, pero una vez que se descarta la hoja, la transición de la vista debajo de la hoja a la página de inicio de sesión es bastante discordante. Sobre todo porque no hay uno. La vista superior simplemente desaparece, revelando la vista de inicio de sesión. Sé que puedo crear transiciones personalizadas, pero no sé dónde adjuntarlo. Digamos, por ejemplo, que quiero atenuar la vista debajo de la hoja. (¡Aunque estoy abierto a cualquier tipo de transición!)
Esta es la estructura que dirige el tráfico:
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
}
}
}
}
Y este es el botón de cerrar sesión en la hoja:
Button(action: {
self.presentationMode.wrappedValue.dismiss()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.tower.currentPage = .login
}
}) {
Text("Sign Out")
}
Respuestas
Aquí hay una demostración simplificada de su código replicado (e hice un retraso más largo para hacerlo visible). Por supuesto, necesitará ajustarlo a sus necesidades cambiando el tipo de transición o animación, etc. Probado con 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")
}
}
}
}