Präsentieren Sie eine neue Ansicht in SwiftUI

11

Ich möchte auf eine Schaltfläche klicken und dann eine neue Ansicht wie present modallyin UIKit präsentieren Geben Sie hier die Bildbeschreibung ein

Ich habe bereits " So präsentieren Sie eine neue Ansicht mithilfe von Blättern " gesehen, möchte sie jedoch nicht als modales Blatt an die Hauptansicht anhängen.

Und ich möchte nicht verwenden NavigationLink, weil ich nicht möchte, dass eine neue Ansicht und eine alte Ansicht eine Navigationsbeziehung haben.

Danke für Ihre Hilfe...

CH Flügel
quelle
Warum möchten Sie es nicht als modales Blatt an die Hauptansicht anhängen? Es ist eine Standardmethode auch in UIKit. Hast du einen besonderen Grund?
Mojtaba Hosseini
Ich versuche meine Gedanken zu erklären ... Wenn etwas nicht stimmt, korrigieren Sie mich bitte.
CH Wing
Die Apps haben 3 Ansichten, 1: Anmeldeseite 2: TableView Seite 3: TableDetail-Seite, TableView-Seite und TableDetail-Seite ist Navigationsbeziehung. Nachdem die Anmeldung auf der TableView-Seite angezeigt wird, hat die TableView-Seite nach der Anmeldung keine Beziehung zur Anmeldeseite
CH Wing
Also musst du es fullscreenrichtig machen?
Mojtaba Hosseini
ys! Ich willfullscreen
CH Wing

Antworten:

12

So zeigen Sie ein Modal an (iOS 13-Stil)

Sie brauchen nur eine einfache sheetmit der Fähigkeit, sich selbst zu entlassen:

struct ModalView: View {
    @Binding var presentedAsModal: Bool
    var body: some View {
        Button("dismiss") { self.presentedAsModal = false }
    }
}

Und präsentieren Sie es wie:

struct ContentView: View {
    @State var presentingModal = false

    var body: some View {
        Button("Present") { self.presentingModal = true }
        .sheet(isPresented: $presentingModal) { ModalView(presentedAsModal: self.$presentingModal) }
    }
}

Beachten Sie, dass ich das presentingModalan das Modal übergeben habe, damit Sie es aus dem Modal selbst entfernen können, aber Sie können es loswerden.


Um es WIRKLICH präsent zu machen fullscreen(nicht nur optisch)

Sie müssen auf die zugreifen ViewController. Sie benötigen also einige Hilfsbehälter und Umgebungsmaterial:

struct ViewControllerHolder {
    weak var value: UIViewController?
}

struct ViewControllerKey: EnvironmentKey {
    static var defaultValue: ViewControllerHolder {
        return ViewControllerHolder(value: UIApplication.shared.windows.first?.rootViewController)

    }
}

extension EnvironmentValues {
    var viewController: UIViewController? {
        get { return self[ViewControllerKey.self].value }
        set { self[ViewControllerKey.self].value = newValue }
    }
}

Dann sollten Sie diese Erweiterung implementieren:

extension UIViewController {
    func present<Content: View>(style: UIModalPresentationStyle = .automatic, @ViewBuilder builder: () -> Content) {
        let toPresent = UIHostingController(rootView: AnyView(EmptyView()))
        toPresent.modalPresentationStyle = style
        toPresent.rootView = AnyView(
            builder()
                .environment(\.viewController, toPresent)
        )
        self.present(toPresent, animated: true, completion: nil)
    }
}

Schließlich

Sie können es fullscreenwie folgt machen :

struct ContentView: View {
    @Environment(\.viewController) private var viewControllerHolder: UIViewController?

    var body: some View {
        Button("Login") {
            self.viewControllerHolder?.present(style: .fullScreen) {
                Text("Main") // Or any other view you like
            }
        }
    }
}
Mojtaba Hosseini
quelle
groß!
CH Wing
Ich erhalte diesen Fehler beim Wrapper für Umgebungseigenschaften: Der Wert vom Typ 'Umgebung <UIViewController?>' Kann nicht in den angegebenen Typ 'UIViewController'
konvertiert werden
Es sollte standardmäßig behandelt werden, aber versuchen Sie es ?am Ende der Zeile hinzuzufügen . @jsbeginnerNodeJS
Mojtaba Hosseini
Ich erhalte diese Fehler in der Konsole: `` `Achtung: Versuchen Sie , das <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7fafd2641d30> auf <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7fafd2611bd0> dessen Ansicht ist in der Fensterhierarchie nicht` ``!
jsbeginnerNodeJS
Wie entlassen Sie es?
gabrielapittari
0

Hier ist eine einfache Einbahnstraße. Es ist sehr einfach.

        struct ChildView: View{
           private  let colors: [Color] = [.red, .yellow,.green,.white]
           @Binding var index : Int
           var body: some View {
           let next = (self.index+1)  % MyContainer.totalChildren
             return   ZStack{
                    colors[self.index  % colors.count]
                     Button("myNextView \(next)   ", action: {
                    withAnimation{
                        self.index = next
                    }
                    }
                )}.transition(.asymmetric(insertion: .move(edge: .trailing)  , removal:  .move(edge: .leading)  ))
            }
        }

        struct MyContainer: View {
            static var totalChildren = 10
            @State private var value: Int = 0
            var body: some View {
                    HStack{
                        ForEach(0..<(Self.totalChildren) ) { index in
                            Group{
                            if    index == self.value {
                                ChildView(index:  self.$value)
                                }}
                            }
                }
                }
        }
E.Coms
quelle
-1

Haftungsausschluss: Im Folgenden wird nicht wirklich wie ein "natives Modal" beschrieben, weder verhalten noch aussehen und sich anfühlen. Wenn jedoch jemand einen benutzerdefinierten Übergang einer Ansicht über eine andere benötigt, um nur die oberste aktiv zu machen, kann der folgende Ansatz hilfreich sein.

Wenn Sie also Folgendes erwarten

benutzerdefiniertes SwiftUI-Modal

Hier ist ein einfacher Code für die Demo des Ansatzes (von Corse Animation & Übergangsparametern können auf Wunsch geändert werden)

struct ModalView : View {
    @Binding var activeModal: Bool
    var body : some View {
        VStack {
            Button(action: {
                withAnimation(.easeInOut(duration: 0.3)) {
                    self.activeModal = false
                }
            }) {
                Text("Hide modal")
            }
            Text("Modal View")
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
        .background(Color.green)
    }
}

struct MainView : View {
    @Binding var activeModal: Bool
    var body : some View {
        VStack {
            Button(action: {
                withAnimation(.easeInOut(duration: 0.3)) {
                    self.activeModal = true
                }
            }) {
                Text("Show modal")
            }
            Text("Main View")
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
        .background(Color.yellow)
    }
}

struct ModalContainer: View {
    @State var showingModal = false
    var body: some View {
        ZStack {
            MainView(activeModal: $showingModal)
                .allowsHitTesting(!showingModal)
            if showingModal {
                ModalView(activeModal: $showingModal)
                    .transition(.move(edge: .bottom))
                    .zIndex(1)
            }
        }
    }
}
Asperi
quelle