SwiftUI - Animer la transition

Sep 05 2020

J'ai un bouton de déconnexion sur une feuille modale qui ramène l'utilisateur à l'écran de connexion. Pour ce faire, je ferme d'abord la feuille puis, en utilisant asyncAfter (date limite :), je définis une variable d'environnement qui fait apparaître la page de connexion. Tout fonctionne bien, mais une fois la feuille supprimée, le passage de la vue sous la feuille à la page de connexion est assez choquant. Surtout parce qu'il n'y en a pas. La vue de dessus disparaît simplement, révélant la vue de connexion. Je sais que je peux créer des transitions personnalisées, mais je ne sais pas où l'attacher. Disons, par exemple, que je souhaite faire disparaître la vue sous la feuille. (Bien que je sois ouvert à tout type de transition!)

C'est la structure qui dirige le trafic:

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

Et voici le bouton de déconnexion sur la feuille:

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

Réponses

1 Asperi Sep 05 2020 at 00:56

Voici une démo simplifiée sur votre code répliqué (et j'ai fait un délai plus long pour le rendre visible en mode). Bien sûr, vous devrez l'adapter à vos besoins en changeant le type de transition ou d'animation, etc. Testé avec 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")
                }
            }
    }
}