NSStatusItem更改暗色调的图像

时间:2014-07-08 04:09:52

标签: objective-c macos osx-yosemite nsstatusitem nsstatusbar

在OSX 10.10 beta 3中,Apple发布了他们的暗色调选项。不幸的是,这也意味着几乎所有的状态栏图标(除了我见过的Apple和Path Finder),包括我的,都在黑暗的背景下保持黑暗。如何在应用深色调时提供替代图像?

我没有看到NSStatusBarNSStatusItem上的API更改显示我发生了更改,我假设它是一个通知,或者因为用户改变了色调而很容易做出改变的事情

绘制图片的当前代码包含在NSView

- (void)drawRect:(NSRect)dirtyRect
{
    // set view background color
    if (self.isActive) {
        [[NSColor selectedMenuItemColor] setFill];
    } else {
        [[NSColor clearColor] setFill];
    }

    NSRectFill(dirtyRect);

    // set image
    NSImage *image = (self.isActive ? self.alternateImage : self.image);
    _imageView.image = image;
}

6 个答案:

答案 0 :(得分:58)

TL; DR:你不必在黑暗主题中做任何特别的事情。为NSStatusItem(或NSStatusBarButton)提供一个模板图像,它将在任何菜单栏上下文中正确设置样式。


某些应用的原因'状态项(例如路径查找器)已经在Dark Theme中工作,因为他们没有在StatusItem上设置自己的自定义视图,而只是在StatusItem上设置模板图像。

类似的东西:

_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
NSImage *image = [NSImage imageNamed:@"statusItemIcon"];
[image setTemplate:YES];
[_statusItem setImage:image];

这与您在Mavericks及其早期以及Yosemite以及任何未来版本中的预期完全相同,因为它允许AppKit 根据状态执行图像的所有样式设置项目状态。

小牛

在小牛队(以及之前),只有2种独特的项目风格。没有压力和压力。这两种风格分别看起来纯粹是黑色和纯白色。 (实际上"纯黑色"不完全正确 - 有一个小的效果,使它们看起来有点插入)。

因为只有两种可能的状态,状态栏应用程序可以设置自己的视图,只需根据突出显示的状态绘制黑色或白色即可轻松获得相同的外观。 (但请注意,它不是纯黑色的,因此应用程序要么必须在图像中构建效果,要么对难以察觉的不合适的图标感到满意。)

优胜美

在约塞米蒂,至少有32种独特的物品造型。黑暗主题中没有压缩只是其中之一。没有实用(或不实用)的方式让应用程序能够自己设置项目样式并使其在所有上下文中看起来都正确。

以下是六种可能的样式的例子:

Six possible status item stylings

非活动菜单栏上的状态项现在具有特定样式,而不是像过去那样简单的不透明度变化。残疾人外表是另一种可能的变化;此可能性矩阵还有其他维度

API

设置为NSStatusItem的view属性的任意视图无法捕获所有这些变体,因此它(以及其他相关API)在10.10中已弃用。

然而,种子3在NSStatusItem上引入了新的API:

@property (readonly, strong) NSStatusBarButton *button NS_AVAILABLE_MAC(10_10);

这条API有一些目的:

  1. 应用程序现在可以获取状态项的屏幕位置(或显示弹出窗口),而无需设置自己的自定义视图。
  2. 在NSStatusItem上删除了对imagetitlesendActionOn:等API的需求。
  3. 为新API提供一个类:即looksDisabled。这允许应用程序获得标准的禁用/关闭样式(如关闭时的蓝牙/时间机器),而无需自定义图像。
  4. 如果使用当前(非自定义视图)API无法完成某些操作,请为其提交增强请求。 StatusItems应该以在所有状态项中标准化的方式提供行为或外观。


    更多讨论发布在https://devforums.apple.com/thread/234839,尽管我已在此总结了大部分内容。

答案 1 :(得分:5)

我最终做了类似跟随我的自定义拖放NSStatusItemView :(使用Swift)

var isDark = false

func isDarkMode() {
    isDark = NSAppearance.currentAppearance().name.hasPrefix("NSAppearanceNameVibrantDark")
}

override func drawRect(dirtyRect: NSRect) {
    super.drawRect(dirtyRect)
    isDarkMode()
    // Now use "isDark" to determine the drawing colour.
    if isDark {
        // ...
    } else {
        // ...
    }
}

当用户在系统偏好设置中更改主题时,系统将调用NSView进行重新绘制,您可以相应地更改图标颜色。

如果您希望在此视图外调整其他自定义UI,您可以使用KVO观察视图的isDark键,也可以自行执行。

答案 2 :(得分:2)

我创建了一个围绕NSStatusItem的基本包装器,您可以使用它在状态栏中为自定义视图提供对10.10及更早版本的支持。您可以在此处找到它:https://github.com/noahsmartin/YosemiteMenuBar基本思想是将自定义视图绘制到NSImage中,并将此图像用作状态栏项的模板图像。此包装器还将单击事件转发到自定义视图,以便可以按照与10.10之前相同的方式处理它们。该项目包含YosemiteMenuBar如何与状态栏上的自定义视图一起使用的基本示例。

答案 3 :(得分:1)

当您的应用程序绘制了任何GUI元素时,您可以通过[NSAppearance currentAppearance]获取其外观,name本身具有NSAppearanceNameVibrantDark->NSAppearanceNameAqua->NSAppearanceNameAquaMavericks 属性,其中包含类似

的内容
NSAppearanceNameVibrantDark

第一部分是外观的名称,在NSAppearanceNameVibrantLight-(void)awakeFromNib { NSStatusItem* myStatusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; myStatusItem.title = @"Hello World"; if ([[[NSAppearance currentAppearance] name] containsString:NSAppearanceNameVibrantDark]) { myStatusItem.title = @"Dark Interface"; } else { myStatusItem.title = @"Light Interface"; } } 中也可以作为常量使用。

我不知道是否有办法获得第一部分,但我认为现在就可以解决这个问题。

示例代码:

{{1}}

答案 4 :(得分:1)

但是,如果您确实希望监控状态更改,则可以。我也知道有一种比上面说的更好的方法来确定精简版/暗模式,但我现在能记住它。

Car truck = new Car();

答案 5 :(得分:1)

最新的快速代码设置图像模板方法在这里:

// Insert code here to initialize your application
if let button = statusItem.button {
    button.image = NSImage(named: "StatusIcon")
    button.image?.isTemplate = true  // Just add this line
    button.action = #selector(togglePopover(_:))
}

然后它将在黑暗模式下更改图像。