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

如何在macOS上使用SwiftUI显示QLPreviewPanel?,swiftui,appkit,quicklook,Swiftui,Appkit,Quicklook,试图找出如何在iOS和macOS上使用SwiftUI中的QuickLook。我怀疑在不久的将来,会有一些统一的SwiftUIQLAPI,但目前还看不到它,所以让我们使用我们现有的 如何从SwiftUI视图中显示和配置QLPreviewPanel?到目前为止,我有: struct ItemView: View { let previewPanelThing = PreviewPanelThing() var body: some View { Button("OSX

试图找出如何在iOS和macOS上使用SwiftUI中的QuickLook。我怀疑在不久的将来,会有一些统一的SwiftUIQLAPI,但目前还看不到它,所以让我们使用我们现有的

如何从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文档中说:
预览面板遵循响应者链,并适应愿意控制它的第一响应者。
My
PreviewPanelhing
实例不在UI和响应者链中。我不确定应答器链在SwiftUI中是如何工作的,以及如何最好地执行它。

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

更新:添加了带有
QLPreviewPanel
的变量,单击按钮

导入快捷界面
导入应用程序包
进口石英
func loadPreviewItem(名称:String)->NSURL{
让file=name.components(以“.”分隔)
让path=Bundle.main.path(forResource:file.first!,类型:file.last!)
让url=NSURL(fileURLWithPath:path!)
返回url
}
结构MyPreview:NSViewRepresentable{
变量文件名:字符串
func makeNSView(上下文:NSViewRepresentableContext)->QLPreviewView{
let preview=QLPreviewView(帧:.0,样式:.normal)
预览?.autostarts=true
preview?.previewItem=loadPreviewItem(带有:文件名)作为QLPreviewItem
返回预览??QLPreviewView()
}
func updateNSView(unsview:QLPreviewView,context:NSViewRepresentableContext){
}
typealias NSViewType=QLPreviewView
}
结构ContentView:View{
让qlCoordinator=qlCoordinator()
var body:一些观点{
//app bundle资源中应包含example.pdf
VStack{
MyPreview(文件名:“example.pdf”)
分隔器()
按钮(“显示面板”){
let panel=qlviewpanel.shared()
面板?.center()
panel?.dataSource=self.qlCoordinator
面板?.MakeKeyandDerfront(无)
}
}
}
类QLCoordinator:NSObject,QLPreviewPanelDataSource{
func previewPanel(uPanel:QLPreviewPanel!,PreviewItem索引:Int)->QLPreviewItem{
将loadPreviewItem(带:“example.pdf”)作为QLViewItem返回
}
func numberOfPreviewItems(在控制器中:QLPreviewPanel)->Int{
返回1
}
}
}

谢谢。我没有意识到我可以直接分配QLEVIEWPANEL数据源。该解决方案工作得很好,但我收到了很多这样的消息:
-[QLEVIEWPANEL setDataSource:]在面板没有控制器时调用-修复此问题,否则很快就会引发此问题。有关-acceptsPreviewPanelControl:/-beginPreviewPanelControl:/-endPreviewPanelControl:.
,请参阅QLPreviewPanel.h中的注释。你知道如何摆脱它们吗?@Asperi我正在努力查看SwiftUI视图中的
MyPreview(…)
和它下面的
按钮中的
QLPreviewPanel
回调之间的关系。这两个有什么关系?@Dominik我想你可以忽略这些警告。我总是在QuickLook的纯AppKit实现中得到这些,所以我认为您不必太担心。
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
        }
    }
}