OS X屏幕保护程序:视网膜缩略图图像

问题描述 投票:7回答:1

我正在使用Xcode的屏幕保护程序模板为OS X开发屏幕保护程序。通过检查系统屏幕保护程序的包装内容,我发现屏幕保护程序的“系统偏好设置”列表中使用的缩略图来自屏幕保护程序包中的两个文件:

thumbnail.png (90x58)
[email protected] (180x116)

我已经创建了两个这样大小的图像,并将它们放置在屏幕保护程序包中。但是,我的视网膜屏幕上的“系统偏好设置”面板似乎正在加载非视网膜资产。这是[email protected]图像的QuickLook预览旁边的“系统偏好设置”面板的屏幕截图:

enter image description here


我没主意了。有谁知道这可能是什么原因以及如何阻止它?我尝试过的事情:

  1. 使用tiff代替PNG。 -结果相同。
  2. 命名视网膜大小的资产thumbnail.png-结果相同。
  3. 在Xcode的构建配置中关闭了“组合高分辨率作品”。 -结果相同。
  4. 完全删除缩略图资源。有趣的是,“系统偏好设置”面板不会返回绘制默认的缩略图图标。而是绘制一个空白的矩形。这使我相信可能会继续进行缓存,因此我花了一些时间试图找出缓存的位置。已清除的偏好设置等

奇数

如果检查系统屏幕保护程序的软件包,则会发现这两个缩略图文件未报告Finder中的尺寸。而且,如果您使用Sketch打开它们,则它们在该应用中均显示为90x58。 (尽管Photoshop将@ 2x资产显示为180x116)。系统屏幕保护程序的缩略图已应用了光泽效果,而我的缩略图自动获得了该效果,即使图像资产不包含该效果也是如此。

我开始认为面板加载/绘制这些图像的方式有些混乱。也许有人知道我不知道的东西?

objective-c xcode macos cocoa screensaver
1个回答
0
投票

我不确定这是否符合解决方案 ...但是在花了很多时间摆弄图像属性并研究了苹果的屏幕保护程序后,我最终遇到了以下黑客,事实证明这很漂亮有效。我不知道这是否违反任何Apple政策,但对我有用™

<<

我们将利用屏幕保护程序作为插件加载到

系统偏好设置

应用程序的事实。-(void)initThumbnail { // Screen savers are loaded as plugins so their main bundle is not // this one, but the host bundle. We need to use the name directly. NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.example.ScreenSaver"]; // We're gonna use the title of the screen saver as seen in the list // of the "Desktop & Screen Saver" window. This is localized name of // the bundle. NSString *saverTitle = bundle.localizedBundleName; // And this is the actual "thumnail.png" resource, with full Retina // quality (if provided). However, without any customary frame. NSImage *saverThumbnail = [bundle imageForResource:@"thumbnail"]; // Locate our top-level window, walk through all subviews in its // content view, and find one with a certain private class which // has a title that matches ours. Then switch thumbnails there. NSWindow *topWindow = self.window; while (topWindow.parentWindow != nil) { topWindow = topWindow.parentWindow; } for (NSView *view in topWindow.contentView.subviewsRecursive) { if ([view.className isEqualToString:@"IndividualSaverIconView"]) { NSString *title = [view performSelector:@selector(title)]; if ([title isEqualToString:saverTitle]) { [view performSelector:@selector(setImage:) withObject:saverThumbnail]; // This hack was sponsored by NeXTSTEP and Objective-C. return; } } } }
这使用以下帮助程序类别,使代码更易读:

@implementation NSBundle (Name) - (NSString *)localizedBundleName { NSString *bundleNameKey = (NSString *)kCFBundleNameKey; NSString *name; // First look for the localized version... if ((name = self.localizedInfoDictionary[bundleNameKey])) { return name; } // ...if there is no localization then use the common one if ((name = self.infoDictionary[bundleNameKey])) { return name; } return nil; } @end

@implementation NSView (Subviews)

- (NSArray<NSView *> *)subviewsRecursive
{
    // We keep adding objects to this array until we exhaust it
    NSMutableArray<NSView *> *subviews = self.subviews.mutableCopy;
    for (NSUInteger i = 0; i < subviews.count; i++) {
        [subviews addObjectsFromArray:[[subviews objectAtIndex:i] subviews]];
    }
    return subviews;
}

@end
请注意,您

无法

initWithFrame:isPreview:中调用此方法,因为此时屏幕保护程序尚未插入视图层次结构中。我发现hasConfigureSheet是个好地方,只需确保只做一次即可。也请注意,缩略图不会自动获得此光泽框。系统屏幕保护程序已内置,您也应该这样做。
© www.soinside.com 2019 - 2024. All rights reserved.