简体   繁体   English

NSStatusItem更改暗色调的图像

[英]NSStatusItem change image for dark tint

With OSX 10.10 beta 3, Apple released their dark tint option. 在OSX 10.10 beta 3中,Apple发布了他们的暗色调选项。 Unfortunately, it also means that pretty much all status bar icons (with the exception of Apple's and Path Finder's that I've seen), including mine, remain dark on a dark background. 不幸的是,这也意味着几乎所有的状态栏图标(除了我见过的Apple和Path Finder),包括我的,都在黑暗的背景下保持黑暗。 How can I provide an alternate image for when dark tint is applied? 如何在应用深色调时提供替代图像?

I don't see an API change on NSStatusBar or NSStatusItem that shows me a change, I'm assuming it's a notification or something reactive to easily make the change as the user alters the tint. 我没有看到NSStatusBarNSStatusItem上的API更改向我显示了一个更改,我假设它是一个通知或一些反应,以便在用户改变色调时轻松进行更改。

Current code to draw the image is encased within an NSView : 绘制图像的当前代码包含在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;
}

TL;DR: You don't have to do anything special in Dark Theme. TL; DR:你不必在黑暗主题中做任何特别的事情。 Give NSStatusItem (or NSStatusBarButton) a template image and it will style it correctly in any menubar context. 为NSStatusItem(或NSStatusBarButton)提供模板图像,它将在任何菜单栏上下文中正确设置样式。


The reason why some apps' status items (such as PathFinder's) already work in Dark Theme is because they're not setting their own custom view on the StatusItem, but only setting a template image on the StatusItem. 某些应用程序的状态项(例如PathFinder)已经在Dark Theme中工作的原因是因为他们没有在StatusItem上设置自己的自定义视图,而只是在StatusItem上设置模板图像。

Something like: 就像是:

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

This works exactly as you'd expect in Mavericks and earlier, as well as Yosemite and any future releases because it allows AppKit to do all of the styling of the image depending on the status item state. 这与您在Mavericks及其早期以及Yosemite以及任何未来版本中的预期完全一样, 因为它允许AppKit根据状态项状态执行图像的所有样式。

Mavericks 小牛

In Mavericks (and earlier) there were only 2 unique styles of the items. 在小牛队(以及之前),只有2种独特的项目风格。 Unpressed and Pressed. 没有压力和压力。 These two styles pretty much looked purely black and purely white, respectively. 这两种风格分别看起来纯粹是黑色和纯白色。 (Actually "purely black" isn't entirely correct -- there was a small effect that made them look slightly inset). (实际上“纯黑色”并不完全正确 - 有一个小的效果,使它们看起来有点插入)。

Because there were only two possible state, status bar apps could set their own view and easily get the same appearance by just drawing black or white depending on their highlighted state. 因为只有两种可能的状态,状态栏应用程序可以设置自己的视图,只需根据突出显示的状态绘制黑色或白色即可轻松获得相同的外观。 (But again note that it wasn't purely black, so apps either had to build the effect in the image or be satisfied with a hardly-noticeable out of place icon). (但再次注意,它不是纯粹的黑色,因此应用程序要么必须在图像中构建效果,要么满足于难以察觉的不合适的位置图标)。

Yosemite 优胜美地

In Yosemite there are at least 32 unique styling of items. 在优胜美地,至少有32种独特的物品造型。 Unpressed in Dark Theme is only one of those. 黑暗主题中没有压缩只是其中之一。 There is no practical (or unpractical) way for an app to be able to do their own styling of items and have it look correct in all contexts. 没有实用(或不实用)的方式让应用程序能够自己设置项目样式并使其在所有上下文中看起来都正确。

Here are examples of six of those possible stylings: 以下是六种可能的样式的示例:

六种可能的状态项目样式

Status items on an inactive menubar now have a specific styling, as opposed to a simple opacity change as in the past. 非活动菜单栏上的状态项目现在具有特定样式,而不像过去那样简单的不透明度变化。 Disabled appearance is one other possible variation; 残疾人外表是另一种可能的变化; there are also other additional dimensions to this matrix of possibilities. 这种可能性矩阵还有其他额外的维度

API API

Arbitrary views set as NSStatusItem's view property have no way to capture all of these variations, hence it (and other related API) is deprecated in 10.10. 设置为NSStatusItem view属性的任意视图无法捕获所有这些变体,因此它(以及其他相关API)在10.10中已弃用。

However, seed 3 introduces new API on NSStatusItem: 但是,种子3在NSStatusItem上引入了新的API:

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

This piece of API has a few purposes: 这篇API有一些目的:

  1. An app can now get the screen position (or show a popover from) a status item without setting its own custom view. 现在,应用程序可以获取状态项的屏幕位置(或显示弹出窗口),而无需设置自己的自定义视图。
  2. Removes the need for API like image , title , sendActionOn: on NSStatusItem. sendActionOn:上删除了对imagetitlesendActionOn:等API的需求。
  3. Provides a class for new API: ie looksDisabled . 为新API提供一个类:ie looksDisabled This allows apps to get the standard disabled/off styling (like Bluetooth/Time Machine when off) without requiring a custom image. 这允许应用程序获得标准的禁用/关闭样式(如关闭时的蓝牙/时间机器),而无需自定义图像。

If there's something that can't be done with the current (non- custom view) API, please file an enhancement request for it. 如果使用当前(非自定义视图)API无法完成某些操作,请为其提交增强请求。 StatusItems should provide behavior or appearances in a way that it standard across all status items. StatusItems应该以在所有状态项中标准化的方式提供行为或外观。


More discussion is at https://devforums.apple.com/thread/234839 , although I've summarized most everything here. 更多讨论请访问https://devforums.apple.com/thread/234839 ,尽管我在这里总结了大部分内容。

I end up did something like following to my custom drag and drop NSStatusItemView : (Using Swift) 我最终做了类似跟随我的自定义拖放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 {
        // ...
    }
}

When the user changed the Theme in System Preferences, the NSView will be called by the system for re-drawing, you can change the icon colour accordingly. 当用户在系统偏好设置中更改主题时,系统将调用NSView进行重新绘制,您可以相应地更改图标颜色。

If you wish to adjust other custom UI outside this view, you can either use KVO to observer the isDark key of the view or do it on your own. 如果您希望在此视图外调整其他自定义UI,则可以使用KVO观察视图的isDark键,也可以自行执行。

I created a basic wrapper around NSStatusItem that you can use to provide support for 10.10 and earlier with custom views in the status bar. 我创建了一个围绕NSStatusItem的基本包装器,您可以使用它在状态栏中为自定义视图提供10.10及更早版本的支持。 You can find it here: https://github.com/noahsmartin/YosemiteMenuBar The basic idea is to draw the custom view into a NSImage and use this image as a template image for the status bar item. 您可以在此处找到它: https//github.com/noahsmartin/YosemiteMenuBar基本思想是将自定义视图绘制到NSImage中,并将此图像用作状态栏项的模板图像。 This wrapper also forwards click events to the custom view so they can be handled the same way as pre 10.10. 此包装器还将单击事件转发到自定义视图,以便可以按照与10.10之前相同的方式处理它们。 The project contains a basic example of how YosemiteMenuBar can be used with a custom view on the status bar. 该项目包含YosemiteMenuBar如何与状态栏上的自定义视图一起使用的基本示例。

When your application has drawn any GUI element you can get its appearance via [NSAppearance currentAppearance] which itself has a name property that holds something like 当你的应用程序绘制了任何GUI元素时,你可以通过[NSAppearance currentAppearance]获得它的外观,它本身有一个name属性,它包含类似的内容

NSAppearanceNameVibrantDark->NSAppearanceNameAqua->NSAppearanceNameAquaMavericks

The first part is the appearance's name, which is also available as a constant in NSAppearanceNameVibrantDark or NSAppearanceNameVibrantLight . 第一部分是外观的名称,也可以在NSAppearanceNameVibrantDarkNSAppearanceNameVibrantLight作为常量NSAppearanceNameVibrantLight

I don't know if there's a way to get just the first part, but I think this does the trick for now. 我不知道是否有办法获得第一部分,但我认为这就是现在的诀窍。

Example code: 示例代码:

-(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";
    }
}

But just in case you do want to monitor the status changes you can. 但是,如果你确实希望监控状态变化,你可以。 I also know there is a better way to determine lite/dark mode than what's been said above, but I can remember it right now. 我也知道有一种比上面说的更好的方法来确定lite / dark模式,但我现在能记住它。

// Monitor menu/dock theme changes...
[[NSDistributedNotificationCenter defaultCenter] addObserver: self selector: @selector(themeChange:) name:@"AppleInterfaceThemeChangedNotification" object: NULL];

//
-(void) themeChange :(NSNotification *) notification
{
    NSLog (@"%@", notification);
}

Newest swift code set image template method is here: 最新的swift代码集图像模板方法在这里:

// 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(_:))
}

Then it will change the image when dark mode. 然后它会在黑暗模式下改变图像。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM