在 iPad 上具有自定义大小的 SwiftUI sheet() 模态

标签 swift ipad swiftui

如何使用 SwiftUI 在 iPad 上控制模态表的首选呈现大小?我很惊讶在谷歌上找到答案是多么困难。

此外,了解模态是否通过向下拖动(取消)或实际执行自定义积极操作来解除模式的最佳方法是什么?

最佳答案

这是我在 SwiftUI 中在 iPad 上显示表单的解决方案:

struct MyView: View {
    @State var show = false

    var body: some View {
        Button("Open Sheet") { self.show = true }
            .formSheet(isPresented: $show) {
                Text("Form Sheet Content")
            }
    }
}
由此 UIViewControllerRepresentable 启用
class FormSheetWrapper<Content: View>: UIViewController, UIPopoverPresentationControllerDelegate {

    var content: () -> Content
    var onDismiss: (() -> Void)?

    private var hostVC: UIHostingController<Content>?

    required init?(coder: NSCoder) { fatalError("") }

    init(content: @escaping () -> Content) {
        self.content = content
        super.init(nibName: nil, bundle: nil)
    }

    func show() {
        guard hostVC == nil else { return }
        let vc = UIHostingController(rootView: content())

        vc.view.sizeToFit()
        vc.preferredContentSize = vc.view.bounds.size

        vc.modalPresentationStyle = .formSheet
        vc.presentationController?.delegate = self
        hostVC = vc
        self.present(vc, animated: true, completion: nil)
    }

    func hide() {
        guard let vc = self.hostVC, !vc.isBeingDismissed else { return }
        dismiss(animated: true, completion: nil)
        hostVC = nil
    }

    func presentationControllerWillDismiss(_ presentationController: UIPresentationController) {
        hostVC = nil
        self.onDismiss?()
    }
}

struct FormSheet<Content: View> : UIViewControllerRepresentable {

    @Binding var show: Bool

    let content: () -> Content

    func makeUIViewController(context: UIViewControllerRepresentableContext<FormSheet<Content>>) -> FormSheetWrapper<Content> {

        let vc = FormSheetWrapper(content: content)
        vc.onDismiss = { self.show = false }
        return vc
    }

    func updateUIViewController(_ uiViewController: FormSheetWrapper<Content>,
                                context: UIViewControllerRepresentableContext<FormSheet<Content>>) {
        if show {
            uiViewController.show()
        }
        else {
            uiViewController.hide()
        }
    }
}

extension View {
    public func formSheet<Content: View>(isPresented: Binding<Bool>,
                                          @ViewBuilder content: @escaping () -> Content) -> some View {
        self.background(FormSheet(show: isPresented,
                                  content: content))
    }
}

您应该可以修改 func show() 中的代码根据 UIKit 规范,以获得您喜欢的大小(如果需要,您甚至可以从 SwiftUI 端注入(inject)参数)。这就是我如何让表单在 iPad 上作为 .sheet 工作对我的用例来说太大了

关于在 iPad 上具有自定义大小的 SwiftUI sheet() 模态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60967872/

相关文章:

swiftui - 为什么手势开始在 SwiftUI 框架外工作?

swift - 按下“点赞”按钮后,Firebase 中如何记录“点赞”?

ios - Swift 认为 Structure 中的变量是可选的

ios - 具有 func 和返回数据的 Firestore 类

iphone - 重置 UITextField 左边距

iphone - 设计和管理类似于设置的 iPhone 应用程序的有效方法

objective-c - 互动书 - 从哪里开始

ios - 如何让替换 View 淡入旧 View 而不是与它交叉淡入淡出?

ios - 在 SwiftUI 中检测并转发屏幕上任意位置的点击

ios - Swift Playground - 对类使用未实现的初始化程序 'init(size:)'