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


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

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

-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)
            }
        }
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.