首页 > 解决方案 > 在 SwiftUI 中呈现新视图

问题描述

我想单击一个按钮,然后像present modally在 UIKit 中 一样呈现一个新视图在此处输入图像描述

我已经看过“如何使用工作表呈现新视图”,但我不想将其作为模式工作表附加到主视图。

而且我不想使用NavigationLink,因为我不希望新视图和旧视图有导航关系。

谢谢你的帮助...

标签: iosswiftui

解决方案


显示模式(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)
            //        }
            }
        }
    }
}

推荐阅读