Apresentar uma nova visualização no SwiftUI


11

Quero clicar em um botão e apresentar uma nova exibição, como present modallyno UIKit insira a descrição da imagem aqui

Eu já vi " Como apresentar uma nova exibição usando planilhas ", mas não quero anexá-la à exibição principal como uma planilha modal.

E não quero usar NavigationLink, porque não quero uma nova exibição e a exibição antiga tenha um relacionamento de navegação.

Obrigado pela ajuda...


Por que você não deseja anexá-lo à vista principal como uma folha modal? É um método padrão, mesmo em UIKit. Você tem algum motivo especial?
— Mojtaba Hosseini

Eu tento explicar meus pensamentos ... Se houver algo errado, por favor me corrija.
— CH Wing

Os aplicativos têm 3 visualizações, 1: Página de login 2: TabelaView Página 3: Página TableDetail, página TableView e página TableDetail é a relação de navegação. Depois que o login for apresentado na página TableView, a página TableView não terá qualquer relação com a página de login após o login
— CH Wing

Então você precisa estar fullscreencerto?
— Mojtaba Hosseini

ys! eu querofullscreen
— CH Ala

Respostas:


12

Para mostrar um modal (estilo iOS 13)

Você só precisa de um simples sheetcom a capacidade de se demitir:

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

E apresente-a como:

struct ContentView: View {
    @State var presentingModal = false

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

Observe que eu passei o presentingModalpara o modal para que você possa descartá-lo do próprio modal, mas você pode se livrar dele.


Para torná-lo realmente presente fullscreen(não apenas visualmente)

Você precisa acessar o ViewController. Então, você precisa de alguns contêineres auxiliares e coisas do ambiente:

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

Então você deve usar implementar esta extensão:

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

você pode fazer fullscreenassim:

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

ótimo! obrigado pela sua solução detalhada
— CH Wing

Eu recebo este erro no invólucro da propriedade de ambiente: Não é possível converter o valor do tipo 'Ambiente <UIViewController?>' Para o tipo especificado 'UIViewController'
— jsbeginnerNodeJS

Ele deve ser tratado por padrão, mas tente adicionar ?no final da linha. @jsbeginnerNodeJS
— Mojtaba Hosseini

Eu recebo este erro no console: `` `Aviso: Tentativa de presente <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7fafd2641d30> em <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7fafd2611bd0> cuja visão não é na hierarquia janela` ``!
— jsbeginnerNodeJS

como você descarta isso?
— gabrielapittari

0

Aqui está uma maneira simples - visualizações avançadas. É muito direto.

        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

Isenção de responsabilidade: abaixo não é realmente como um "modal nativo", não se comporta nem parece, mas se alguém precisar de uma transição personalizada de uma visualização sobre outra, ativando apenas a primeira, a abordagem a seguir pode ser útil.

Então, se você espera algo como o seguinte

modal SwiftUI personalizado

Aqui está um código simples para demonstração da abordagem (os parâmetros de animação e transição da corse podem ser alterados por desejo)

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)
            }
        }
    }
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.