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

3

我想了解如何在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文档说:预览面板遵循响应者链并适应第一个愿意控制它的响应者。我的previewPanelThing实例不在UI和响应者链中。我不确定在SwiftUI中响应者链是如何工作的,以及最好的解决方法是什么。


所以三年后,我们在SwiftUI上有了.quickLookPreview()修饰符,在iOS上运行良好,但在macOS上无法正确关闭,并且会出现以下警告,例如“-[QLPreviewPanel reloadData] called while the panel has no controller - Fix this or this will raise soon. See comments in QLPreviewPanel.h for”。我猜目前还没有人解决这个问题?我猜这是苹果的问题。 - undefined
1个回答

6
这里提供了一种使用 QLPreviewView 直接预览 PDF 文件的可能方法(在此演示中存储在主应用程序捆绑包中,但这不会改变常见想法)。 < p >更新:添加了按钮点击时使用 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
        }
    }
}

4
这个解决方案的效果非常好,但是我收到了很多这样的消息:-[QLPreviewPanel setDataSource:] called while the panel has no controller - Fix this or this will raise soon. See comments in QLPreviewPanel.h for -acceptsPreviewPanelControl:/-beginPreviewPanelControl:/-endPreviewPanelControl:. 。你有什么办法消除它们吗? - undefined
@Asperi我很难看出SwiftUI视图中MyPreview(...)和下方的QLPreviewPanelButton回调中是如何相关的。它们之间有什么关联? - undefined
2
@Dominik 我觉得你可以忽略那些警告。我在纯AppKit实现的QuickLook中总是会收到这些警告,所以我认为你不需要太担心。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接