Przedstaw nowy widok w SwiftUI

11

Chcę kliknąć przycisk, a następnie zaprezentować nowy widok, jak present modallyw UIKit wprowadź opis zdjęcia tutaj

Widziałem już „ Jak zaprezentować nowy widok za pomocą arkuszy ”, ale nie chcę dołączać go do widoku głównego jako arkusza modalnego.

Nie chcę używać NavigationLink, ponieważ nie chcę nowego widoku, a stary widok ma relację nawigacyjną.

Dzięki za pomoc...

Skrzydło CH
źródło
Dlaczego nie chcesz dołączyć go do widoku głównego jako arkusza modalnego? Jest to standardowa metoda nawet w UIKit. Czy masz jakiś szczególny powód?
Mojtaba Hosseini
Próbuję wyjaśnić swoje myśli ... Jeśli coś jest nie tak, popraw mnie.
CH Wing
Aplikacje mają widok 3, 1: Strona logowania 2: Strona TableView 3: Strona TableDetail, strona TableView i strona TableDetail to relacja nawigacyjna. Po zalogowaniu się pojawi się na stronie TableView, strona TableView nie ma żadnego związku ze stroną logowania po zalogowaniu
CH Wing
Więc musisz mieć fullscreenrację?
Mojtaba Hosseini
tak! Chcęfullscreen
CH Wing

Odpowiedzi:

12

Aby wyświetlić modalność (styl iOS 13)

Wystarczy prosty sheetze zdolnością do samodzielnego zwolnienia:

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

I przedstaw go w następujący sposób:

struct ContentView: View {
    @State var presentingModal = false

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

Zauważ, że przekazałem presentingModalgo modalowi, abyś mógł go usunąć z samego modalu, ale możesz się go pozbyć.


Aby NAPRAWDĘ był obecny fullscreen(nie tylko wizualnie)

Musisz uzyskać dostęp do ViewController. Potrzebujesz więc pojemników pomocniczych i elementów środowiska:

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

Następnie użyj implementacji tego rozszerzenia:

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

Wreszcie

możesz zrobić to fullscreentak:

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
źródło
świetny! dzięki za szczegółowe rozwiązanie
CH Wing
Ten błąd pojawia się w opakowaniu właściwości środowiska: Nie można przekonwertować wartości typu „Środowisko <UIViewController?>” Na określony typ „UIViewController”
jsbeginnerNodeJS
Powinno być obsługiwane domyślnie, ale spróbuj dodać tam ?na końcu linii. @jsbeginnerNodeJS
Mojtaba Hosseini
Otrzymuję ten błąd w konsoli: `` `Warning: próba przedstawienia <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7fafd2641d30> na <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7fafd2611bd0>, którego widok nie jest w hierarchii okna` ``!
jsbeginnerNodeJS
jak to odrzucasz?
gabrielapittari
0

Oto prosty jeden sposób - widoki do przodu. To bardzo proste.

        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
źródło
-1

Oświadczenie: poniżej nie jest tak naprawdę „natywny”, nie zachowuje się, nie wygląda i nie działa, ale jeśli ktoś będzie potrzebował niestandardowego przejścia jednego widoku na drugi, czyniąc z niego aktywny tylko jeden, inne podejście może być pomocne.

Jeśli więc spodziewasz się czegoś takiego

niestandardowy modalny SwiftUI

Oto prosty kod do demonstracji podejścia (animacji poprawek i parametrów przejścia można zmienić na życzenie)

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
źródło