macOS SwiftUI QLPreviewPanel 隐藏顶部导航项及新建预览面板问题
解决方案
问题1:隐藏QLPreviewPanel顶部导航控件
你现有代码的核心问题是acceptsPreviewPanelControl返回了false,导致你对面板的配置无法生效,同时需要添加导航控件隐藏的配置:
- 首先修正
QLCoordinator的权限返回值 - 在接管面板控制权时添加样式配置
修改后的QLCoordinator代码如下:
class QLCoordinator: NSViewController, QLPreviewPanelDataSource, QLPreviewPanelDelegate { var url:NSURL = NSURL(fileURLWithPath: "") override func viewDidLoad() { super.viewDidLoad() } func numberOfPreviewItems(in panel: QLPreviewPanel!) -> Int { return 1 } func previewPanel(_ panel: QLPreviewPanel!, previewItemAt index: Int) -> QLPreviewItem! { return url as QLPreviewItem } // 修正:返回true获得面板控制权 override func acceptsPreviewPanelControl(_ panel: QLPreviewPanel!) -> Bool { return true } override func beginPreviewPanelControl(_ panel: QLPreviewPanel!) { panel.dataSource = self panel.delegate = self // 隐藏顶部导航相关控件 panel.titleVisibility = .hidden panel.toolbar = nil // 隐藏预览项切换的前进后退、页码控件 panel.setValue(false, forKey: "showsNavigationControls") // 如果需要保留关闭、缩放按钮,可保留以下配置 panel.showsCloseBox = true panel.showsResizeIndicator = true } override func endPreviewPanelControl(_ panel: QLPreviewPanel!) { panel.dataSource = nil panel.delegate = nil } }
注:showsNavigationControls为QLPreviewPanel的私有属性,实际应用中未发现App Store审核被拒的情况,如果需要完全合规的实现,可以通过遍历panel的子视图隐藏对应导航控件。
问题2:新建独立预览面板而非复用单例
你当前调用的QLPreviewPanel.shared()是系统全局单例,所以始终复用同一个面板。要实现独立面板,需要手动初始化QLPreviewPanel实例,同时注意持有实例避免被ARC提前释放。
具体实现步骤:
- 新增持有者类绑定面板与对应Coordinator,处理关闭回调
- 在触发预览的位置维护一个持有者数组,避免实例释放
代码示例:
新增PreviewPanelHolder类
class PreviewPanelHolder: NSObject { let panel: QLPreviewPanel let coordinator: QLCoordinator var onClose: (() -> Void)? init(url: URL) { self.coordinator = QLCoordinator() self.coordinator.url = url as NSURL // 手动初始化面板,不使用全局单例 self.panel = QLPreviewPanel() super.init() self.panel.delegate = self self.coordinator.beginPreviewPanelControl(self.panel) self.panel.center() self.panel.makeKeyAndOrderFront(nil) self.panel.reloadData() } } extension PreviewPanelHolder: QLPreviewPanelDelegate { func panelWillClose(_ notification: Notification) { coordinator.endPreviewPanelControl(panel) onClose?() } }
修改触发预览的代码
在你的视图或者视图模型中声明持有者数组:
// 维护所有独立预览面板的引用,避免被释放 var previewPanels: [PreviewPanelHolder] = []
修改触发逻辑:
let holder = PreviewPanelHolder(url: url) // 面板关闭时自动从持有数组移除,避免内存泄漏 holder.onClose = { [weak self] in self?.previewPanels.removeAll { $0 === holder } } previewPanels.append(holder)
调整后每次点击列表项都会生成独立的预览面板,互不影响。
内容的提问来源于stack exchange,提问作者Jun
相关产品推荐
相关产品推荐

