SwiftUI - Übergang animieren

Sep 05 2020

Ich habe eine Abmeldeschaltfläche auf einem Modalblatt, die den Benutzer zum Anmeldebildschirm zurückführt. Um dies zu erreichen, entlasse ich zuerst das Blatt und setze dann mit asyncAfter (Deadline :) eine Umgebungsvariable, die bewirkt, dass die Anmeldeseite angezeigt wird. Alles funktioniert einwandfrei, aber sobald das Blatt geschlossen ist, ist der Übergang von der Ansicht unter dem Blatt zur Anmeldeseite ziemlich erschütternd. Meistens, weil es keinen gibt. Die Draufsicht verschwindet einfach und zeigt die Anmeldeansicht an. Ich weiß, dass ich benutzerdefinierte Übergänge erstellen kann, aber ich kann nicht herausfinden, wo ich sie anhängen soll. Angenommen, ich möchte die Ansicht unter dem Blatt ausblenden. (Obwohl ich für jede Art von Übergang offen bin!)

Dies ist die Struktur, die den Verkehr lenkt:

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

Und dies ist die Abmeldeschaltfläche auf dem Blatt:

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

Antworten

1 Asperi Sep 05 2020 at 00:56

Hier ist eine vereinfachte Demo zu Ihrem replizierten Code (und ich habe einige längere Verzögerungen vorgenommen, um den Modus sichtbar zu machen). Natürlich müssen Sie es an Ihre Bedürfnisse anpassen, indem Sie die Art des Übergangs oder der Animation usw. ändern. Getestet mit 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")
                }
            }
    }
}