Presenta una nuova vista in SwiftUI


11

Voglio fare clic su un pulsante e quindi presentare una nuova vista come present modallyin UIKit inserisci qui la descrizione dell'immagine

Ho già visto " Come presentare una nuova vista usando i fogli ", ma non voglio collegarla alla vista principale come un foglio modale.

E non voglio usare NavigationLink, perché non voglio una nuova vista e la vecchia vista ha una relazione di navigazione.

Grazie per l'aiuto...


Perché non vuoi collegarlo alla vista principale come un foglio modale? È un metodo standard anche in UIKit. Hai qualche motivo speciale?
Mojtaba Hosseini,

Cerco di spiegare i miei pensieri ... Se c'è qualcosa di sbagliato, per favore correggimi.
CH Wing

Le app hanno 3 visualizzazioni, 1: Pagina di accesso 2: Pagina TableView 3: Pagina TableDetail, Pagina TableView e Pagina TableDetail è una relazione di navigazione. Dopo il login si presenterà alla pagina TableView, la pagina TableView non ha alcuna relazione con la pagina di login dopo il login
CH Wing

Quindi hai bisogno che sia fullscreengiusto?
Mojtaba Hosseini,

ys! Vogliofullscreen
CH Wing

Risposte:


12

Per mostrare un modale (stile iOS 13)

Hai solo bisogno di un semplice sheetcon la possibilità di ignorare se stesso:

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

E presentalo come:

struct ContentView: View {
    @State var presentingModal = false

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

Nota che ho passato il presentingModalmodale in modo da poterlo eliminare dal modale stesso, ma puoi liberartene.


Per renderlo DAVVERO presente fullscreen(non solo visivamente)

Devi accedere a ViewController. Quindi hai bisogno di alcuni contenitori di supporto e roba ambientale:

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

Quindi dovresti usare implementare questa estensione:

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

Finalmente

puoi farlo fullscreencome:

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

grande! grazie per la tua soluzione dettagliata
CH Wing

Ottengo questo errore nel wrapper della proprietà ambiente: Impossibile convertire il valore di tipo 'Environment <UIViewController?>' Nel tipo specificato 'UIViewController'
jsbeginnerNodeJS

Dovrebbe essere gestito per impostazione predefinita, ma prova ad aggiungere ?lì alla fine della riga. @jsbeginnerNodeJS
Mojtaba Hosseini,

Ottengo questo errore nella console: `` `Attenzione: tentativo di presentare <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7fafd2641d30> on <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7fafd2611bd0> la cui vista non è nella gerarchia finestra di` ``!
jsbeginnerNodeJS

come lo respingi?
gabrielapittari,

0

Ecco un semplice modo: le viste in avanti. È molto semplice.

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

-1

Disclaimer: di seguito non è proprio come un "modale nativo", né si comporta né si guarda e si sente, ma se qualcuno avesse bisogno di una transizione personalizzata di una vista sull'altra, rendendola attiva solo in cima, il seguente approccio potrebbe essere utile.

Quindi, se ti aspetti qualcosa di simile al seguente

modale SwiftUI personalizzato

Ecco un semplice codice per la dimostrazione dell'approccio (i parametri di animazione e transizione di corse possono essere modificati a piacere)

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)
            }
        }
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.