簡體   English   中英

在 SwiftUI 中呈現新視圖

[英]Present a new view in SwiftUI

我想單擊一個按鈕,然后在 UIKit 中以present modally方式呈現一個新視圖在此處輸入圖像描述

我已經看過“ 如何使用工作表呈現新視圖”,但我不想將其作為模式工作表附加到主視圖。

而且我不想使用NavigationLink ,因為我不希望新視圖和舊視圖有導航關系。

謝謝你的幫助...

顯示模式(iOS 13 風格)

您只需要一張能夠自行關閉的簡單sheet

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

並將其呈現為:

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

請注意,我將presentingModal傳遞給模態,因此您可以將其從模態本身中消除,但您可以擺脫它。


讓它真正呈現fullscreen (不僅僅是視覺上)

您需要訪問ViewController 所以你需要一些輔助容器和環境的東西:

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

然后你應該使用實現這個擴展:

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)
        )
        NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: "dismissModal"), object: nil, queue: nil) { [weak toPresent] _ in
            toPresent?.dismiss(animated: true, completion: nil)
        }
        self.present(toPresent, animated: true, completion: nil)
    }
}

最后

你可以讓它fullscreen像:

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
// uncomment and add the below button for dismissing the modal
            // Button("Cancel") {
            //       NotificationCenter.default.post(name: Notification.Name(rawValue: "dismissModal"), object: nil)
            //        }
            }
        }
    }
}

對於 iOS 14 和 Xcode 12:

struct ContentView: View {
    @State private var isPresented = false

var body: some View {
    Button("Show Modal with full screen") {
        self.isPresented.toggle()
    }
    .fullScreenCover(isPresented: $isPresented, content: FullScreenModalView.init)
    }
}
struct FullScreenModalView: View {
     @Environment(\.presentationMode) var presentationMode

var body: some View {
    VStack {
        Text("This is a modal view")
    }
    .frame(maxWidth: .infinity, maxHeight: .infinity)
    .background(Color.red)
    .edgesIgnoringSafeArea(.all)
    .onTapGesture {
        presentationMode.wrappedValue.dismiss()
    }
}
}

希望這個答案可以幫助到大家。 在下面評論您的結果。

參考: 此鏈接

免責聲明:下面並不是真正的“本機模式”,既不是行為也不是外觀和感覺,但如果有人需要一個視圖的自定義轉換,只激活頂部視圖,以下方法可能會有所幫助。

因此,如果您期望以下內容

自定義 SwiftUI 模態

這是演示方法的簡單代碼(可根據需要更改 animation 和轉換參數)

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)
                .disabled(showingModal)
            if showingModal {
                ModalView(activeModal: $showingModal)
                    .transition(.move(edge: .bottom))
                    .zIndex(1)
            }
        }
    }
}

備份

這是一種簡單的方法——前瞻觀點。 這是非常直接的。

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

然后在點擊按鈕時從 ContentView 呈現它:

struct SheetView: View {
        @Environment(\.dismiss) var dismiss
    
        var body: some View {
            Button("Press to dismiss") {
                dismiss()
            }
            .font(.title)
            .padding()
            .background(Color.black)
        }
    }
    
    struct ContentView: View {
        @State private var showingSheet = false
    
        var body: some View {
            Button("Show Sheet") {
                showingSheet.toggle()
            }
            .sheet(isPresented: $showingSheet) {
                SheetView()
            }
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM