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.