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

Jaa*_*nus 3 quicklook appkit swiftui

尝试弄清楚如何在 iOS 和 macOS 上的 SwiftUI 中使用 QuickLook。我怀疑在不久的将来,将会有一些统一的 SwiftUI QL API,但是 \xe2\x80\x99 还看不到它,所以让 \xe2\x80\x99s 使用我们拥有的 \xe2\x80\xa6

\n\n

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

\n\n
struct ItemView: View {\n    let previewPanelThing = PreviewPanelThing()\n    var body: some View {\n        Button("OSX preview") {\n            print("osx preview")\n            if let previewPanel = QLPreviewPanel.shared() {\n                self.previewPanelThing.updateControllerForPanel(previewPanel)\n                previewPanel.makeKeyAndOrderFront(self.previewPanelThing)\n            }                   \n        }\n    }\n}\n\nclass PreviewPanelThing: QLPreviewPanelDataSource {\n\n    func updateControllerForPanel(_ panel: QLPreviewPanel) {\n        print("updating controller")\n        panel.updateController()\n    }\n\n    func numberOfPreviewItems(in panel: QLPreviewPanel!) -> Int {\n        print("number of items")\n        return 1\n    }\n\n    func previewPanel(_ panel: QLPreviewPanel!, previewItemAt index: Int) -> QLPreviewItem! {\n        print("requesting preview item")\n        let fileURL: URL = Bundle.main.url(forResource: "Thinking-of-getting-a-cat", withExtension: "png")!\n        return fileURL as QLPreviewItem\n    }   \n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是 \xe2\x80\x99 无法工作的。我怀疑这是因为 QLPreviewPanel 文档说:The preview panel follows the responder chain and adapts to the first responder willing to control it.我的previewPanelThing实例在 UI 和响应程序链中是\xe2\x80\x99t。我\xe2\x80\x99m 不确定响应者链在 SwiftUI 中如何工作以及如何最好地进行它。

\n

Asp*_*eri 7

这是直接使用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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 该解决方案工作得很好,但我收到很多类似这样的消息:`-[QLPreviewPanel setDataSource:] 在面板没有控制器时调用 - 修复此问题,否则很快就会引发此问题。请参阅 QLPreviewPanel.h 中 -acceptsPreviewPanelControl:/-beginPreviewPanelControl:/-endPreviewPanelControl:.` 的注释。你知道如何摆脱它们吗? (4认同)
  • @Dominik我认为你可以忽略这些警告。我总是在 QuickLook 的纯 AppKit 实现中获得这些,所以我认为您不需要太担心。 (2认同)