如何在 macOS 上使用 SwiftUI 显示 QLPreviewPanel?

How do I show QLPreviewPanel with SwiftUI on macOS?

试图弄清楚如何在 iOS 和 macOS 上使用 SwiftUI 中的 QuickLook。我怀疑在不久的将来,会有一些统一的 SwiftUI QL API,但目前还看不到,所以让我们利用现有的东西吧……

如何从我的 SwiftUI 视图显示和配置 QLPreviewPanel?到目前为止,我有这个:

struct ItemView: View {
    let previewPanelThing = PreviewPanelThing()
    var body: some View {
        Button("OSX preview") {
            print("osx preview")
            if let previewPanel = QLPreviewPanel.shared() {
                self.previewPanelThing.updateControllerForPanel(previewPanel)
                previewPanel.makeKeyAndOrderFront(self.previewPanelThing)
            }                   
        }
    }
}

class PreviewPanelThing: QLPreviewPanelDataSource {

    func updateControllerForPanel(_ panel: QLPreviewPanel) {
        print("updating controller")
        panel.updateController()
    }

    func numberOfPreviewItems(in panel: QLPreviewPanel!) -> Int {
        print("number of items")
        return 1
    }

    func previewPanel(_ panel: QLPreviewPanel!, previewItemAt index: Int) -> QLPreviewItem! {
        print("requesting preview item")
        let fileURL: URL = Bundle.main.url(forResource: "Thinking-of-getting-a-cat", withExtension: "png")!
        return fileURL as QLPreviewItem
    }   
}

这是行不通的。我怀疑这是因为 QLPreviewPanel 文档说:The preview panel follows the responder chain and adapts to the first responder willing to control it. 我的 previewPanelThing 实例不在 UI 和响应者链中。我不确定响应链在 Swift 中是如何工作的UI 以及如何最好地处理它。

这里是使用 QLPreviewView 直接预览 PDF 文件的可能方法(在这个演示中存储在主应用程序包中,但这不会改变共同的想法)

更新:添加了 QLPreviewPanel 按钮点击变体

import SwiftUI
import AppKit
import Quartz

func loadPreviewItem(with name: String) -> NSURL {

    let file = name.components(separatedBy: ".")
    let path = Bundle.main.path(forResource: file.first!, ofType: file.last!)
    let url = NSURL(fileURLWithPath: path!)

    return url
}

struct MyPreview: NSViewRepresentable {
    var fileName: String

    func makeNSView(context: NSViewRepresentableContext<MyPreview>) -> QLPreviewView {
        let preview = QLPreviewView(frame: .zero, style: .normal)
        preview?.autostarts = true
        preview?.previewItem = loadPreviewItem(with: fileName) as QLPreviewItem
        return preview ?? QLPreviewView()
    }

    func updateNSView(_ nsView: QLPreviewView, context: NSViewRepresentableContext<MyPreview>) {
    }

    typealias NSViewType = QLPreviewView

}

struct ContentView: View {
    let qlCoordinator = QLCoordinator()

    var body: some View {

        // example.pdf is expected in app bundle resources
        VStack {
            MyPreview(fileName: "example.pdf")
            Divider()
            Button("Show panel") {
                let panel = QLPreviewPanel.shared()
                panel?.center()
                panel?.dataSource = self.qlCoordinator
                panel?.makeKeyAndOrderFront(nil)
            }
        }
    }

    class QLCoordinator: NSObject, QLPreviewPanelDataSource {
        func previewPanel(_ panel: QLPreviewPanel!, previewItemAt index: Int) -> QLPreviewItem! {
            return loadPreviewItem(with: "example.pdf") as QLPreviewItem
        }

        func numberOfPreviewItems(in controller: QLPreviewPanel) -> Int {
            return 1
        }
    }
}