You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在App内使用QuickLookUI显示SVG文件?

如何在App内使用QuickLookUI显示SVG文件?

我完全懂你遇到的困扰——旧代码能正常展示普通图片,但SVG文件就是搞不定,明明Finder里用QuickLook按空格就能轻松预览,自己的App里却没法复现这个功能。好在从macOS 15开始,NSImageView已经内置支持_NSSVGImageRep来显示SVG,要是想实现像Finder那样用QuickLook面板预览SVG,我们可以自定义NSImageView子类,集成QLPreviewPanel来搞定。

完整实现代码

下面是可直接使用的自定义ImageView子类代码,包含了所有QuickLook预览的核心逻辑:

#import <QuickLookUI/QuickLookUI.h>
#import <Carbon/Carbon.h>
#import "ViewController.h"

@interface QLPreviewImageView : NSImageView <QLPreviewPanelDataSource, QLPreviewPanelDelegate>
@property QLPreviewPanel *previewPanel;
@end

@implementation QLPreviewImageView

// 允许鼠标获取控件焦点
- (BOOL)acceptsFirstResponder {
    return YES;
}

// 允许键盘获取控件焦点
- (BOOL)canBecomeKeyView {
    return YES;
}

// 鼠标双击触发预览面板
- (void)mouseDown:(NSEvent *)event {
    if ([event clickCount] == 2) {
        [self togglePreviewPanel];
    } else {
        [super mouseDown:event];
    }
}

// 空格键触发预览面板(和Finder逻辑一致)
- (void)keyDown:(NSEvent *)event {
    if (event.keyCode == kVK_Space) {
        [self togglePreviewPanel];
    } else {
        [super keyDown:event];
    }
}

// 切换预览面板的显示/隐藏状态
- (void)togglePreviewPanel {
    if ([QLPreviewPanel sharedPreviewPanelExists]) {
        if ([[QLPreviewPanel sharedPreviewPanel] isVisible]) {
            [[QLPreviewPanel sharedPreviewPanel] orderOut:self];
        } else {
            [[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:self];
        }
    } else {
        [[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:self];
    }
}

// MARK: - QLPreviewPanel 控制相关方法
- (BOOL)acceptsPreviewPanelControl:(id)sender {
    return YES;
}

- (void)beginPreviewPanelControl:(QLPreviewPanel *)panel {
    self.previewPanel = panel;
    self.previewPanel.delegate = self;
    self.previewPanel.dataSource = self;
}

- (void)endPreviewPanelControl:(QLPreviewPanel *)panel {
    [self setPreviewPanel:nil];
}

// MARK: - QLPreviewPanelDataSource 数据源方法
// 返回要预览的SVG文件URL,这里示例从主Bundle取,可根据实际场景修改
- (NSURL *)URLForImage {
    NSURL *URL = [[NSBundle mainBundle] URLForResource:@"untitled_i" withExtension:@"svg"];
    return URL;
}

- (id <QLPreviewItem>)previewPanel:(QLPreviewPanel *)panel previewItemAtIndex:(NSInteger)index {
    return [self URLForImage];
}

- (NSInteger)numberOfPreviewItemsInPreviewPanel:(QLPreviewPanel *)panel {
    return [self URLForImage] != nil ? 1 : 0;
}

// MARK: - QLPreviewPanelDelegate 代理方法
// 预览过渡动画的源图片
- (NSImage *)previewPanel:(QLPreviewPanel *)panel transitionImageForPreviewItem:(id <QLPreviewItem>)item contentRect:(CGRect *)aRect {
    return [self image];
}

// 预览过渡动画的源位置
- (CGRect)previewPanel:(QLPreviewPanel *)panel sourceFrameOnScreenForPreviewItem:(id <QLPreviewItem>)item {
    return [self.window convertRectToScreen:[self convertRect:[[self cell] drawingRectForBounds:[self bounds]] toView:nil]];
}

- (BOOL)previewPanel:(QLPreviewPanel *)panel handleEvent:(NSEvent *)event {
    return NO;
}

@end

关键功能说明

  • 触发逻辑:和Finder操作完全对齐,支持两种触发方式:
    • 鼠标双击当前ImageView
    • 当ImageView获得焦点时,按空格键
  • QuickLook集成
    • 通过QLPreviewPanelDataSource提供要预览的SVG文件路径
    • 通过QLPreviewPanelDelegate实现过渡动画,让预览体验和系统原生一致
  • 焦点处理:重写acceptsFirstRespondercanBecomeKeyView,确保控件能接收鼠标和键盘事件

注意事项

  1. 文件路径适配:示例里URLForImage是从主Bundle读取SVG,你需要根据实际业务修改这个方法,比如从沙盒、用户选中的文件路径获取URL
  2. 系统版本要求:确保App部署目标不低于macOS 10.15,因为_NSSVGImageRep是从这个版本开始内置支持的
  3. 框架依赖:项目里要记得引入QuickLookUICarbon框架,不然会出现编译错误

火山引擎 最新活动