【问题标题】:NSStatusItem change image for dark tintNSStatusItem 将图像更改为暗色调
【发布时间】:2014-07-08 04:09:51
【问题描述】:

在 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;
}

【问题讨论】:

  • 您是在自定义视图的-drawRect: 中手动绘制图像吗?改用NSImageView 子视图有帮助吗?
  • @KenThomases 应该添加当前代码。它现在就在那里。
  • 您应该使用-drawStatusBarBackgroundInRect:withHighlight:,而不是填充您自己选择的颜色。如果这样做没有帮助,您可以尝试在图像视图上设置背景样式。当然,这就提出了如何选择合适的风格的问题。另外,我会将图像视图的图像设置移动到-viewWillDraw。这种事情不应该在-drawRect:做。
  • 感谢您的意见,但我相信您误会了。背景在适当的时候变暗,它的前景图像在现在黑暗的背景上仍然是一个黑暗的图像。我需要知道何时将其替换为白色前景图像。
  • 我的意思是NSImageView 很有可能可以区分填充了您选择的颜色的背景和使用我提到的适当方法绘制的背景之间的区别。它可能会相应地改变其行为。另外,您使用的是模板图像吗?

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


【解决方案1】:

TL;DR:你不必在 Dark Theme 中做任何特别的事情。给 NSStatusItem(或 NSStatusBarButton)一个模板图像,它会在任何菜单栏上下文中正确地设置它的样式。


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

类似:

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

这与您在 Mavericks 和更早版本以及 Yosemite 和任何未来版本中所期望的完全一样,因为它允许 AppKit 根据状态项状态对图像进行所有样式设置.

小牛队

在 Mavericks(和更早的版本)中,只有 2 种独特风格的物品。未按和按。这两种风格几乎分别看起来是纯黑色和纯白色。 (实际上“纯黑色”并不完全正确——有一个小效果使它们看起来有点内嵌)。

因为只有两种可能的状态,所以状态栏应用可以设置自己的视图,并通过根据突出显示的状态仅绘制黑色或白色来轻松获得相同的外观。 (但请再次注意,它并不是纯黑色,因此应用程序要么必须在图像中构建效果,要么满足于几乎不明显的不合适的图标)。

优胜美地

在优胜美地,至少有 32 种独特的物品样式。 Unpressed in Dark Theme 只是其中之一。没有任何实用(或不实用)的方法可以让应用程序自行设置项目样式并使其在所有情况下看起来都正确。

以下是其中六种可能样式的示例:

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

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。这允许应用获得标准的禁用/关闭样式(例如关闭时的蓝牙/Time Machine),而无需自定义图像。

如果当前(非自定义视图)API 无法完成某些操作,请提交增强请求。 StatusItems 应该以它在所有状态项中标准化的方式提供行为或外观。


更多讨论请访问https://devforums.apple.com/thread/234839,尽管我已经在这里总结了大部分内容。

【讨论】:

  • 注意:在种子 3 中,使用[self.statusItem.button sendActionOn:(NSLeftMouseUpMask|NSRightMouseUpMask)]; 存在问题,右键单击事件不会触发。这里有一个开放的雷达:openradar.appspot.com/radar?id=5882037839855616
  • 您还可以在图像文件名中插入“模板”后缀,例如“MyIconTemplate.png”,它可以开箱即用。顺便提一下它的工作原理,我能够通过将黑色图标文件的最后 8 个字符替换为“模板”并使用 HEX 编辑器编辑编译构建中的文件引用来破解编译的应用程序。现在它就像一个魅力! :)
  • 目前 NSStatusItem 上的 imagesetImage 从 10.10 开始也已弃用
  • 是的。对于 10.10 及更高版本,您应该只在 StatusItem 的按钮上设置图像(在 10.10 上可用)
  • 这是一个基于 os x 版本处理菜单栏的小库。可作为样本:github.com/dmitrynikolaev/MenuBarController
【解决方案2】:

我最终做了一些类似于我的自定义拖放操作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 键,也可以自己进行。

【讨论】:

  • 是 NSStatusItem 中唯一缺少的需要使用自定义视图的拖放行为吗?您是否提交了雷达请求它支持它?
  • @Taylor 现在,是的。不,我没有要求。
【解决方案3】:

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

【讨论】:

  • 看起来很有用,你如何处理加载微调器等动态元素?
【解决方案4】:

最新的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(_:))
}

然后它会在黑暗模式下改变图像。

【讨论】:

    【解决方案5】:

    当您的应用程序绘制了任何 GUI 元素时,您可以通过 [NSAppearance currentAppearance] 获得它的外观,它本身有一个 name 属性,其中包含类似的东西

    NSAppearanceNameVibrantDark->NSAppearanceNameAqua->NSAppearanceNameAquaMavericks
    

    第一部分是外观的名称,在NSAppearanceNameVibrantDarkNSAppearanceNameVibrantLight 中也可以作为常量使用。

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

    示例代码:

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

    【讨论】:

    • 感谢您的意见。关于根据变化进行更改的任何想法?有通知吗?我可能会使用 KVO,但我认为有比这更好的方法,因为路径查找器在 beta 3 发布后就已经工作了。
    • 如果在状态项运行时更改主题,则不会自动调整。
    • @JoelFischer 你试过 KVO 方法了吗?我尝试使用NSAppearance.currentAppearance().addObserver(self,forKeyPath:"name",options: NSKeyValueObservingOptions.Prior,context: nil) 之类的东西,它可以检测到更改,但会导致错误An instance 0x608000465cc0 of class NSCompositeAppearance was deallocated while key value observers were still registered with it.。不知道如何解决。
    • @x43x61x69 我没有测试过,但据我所知,改变的不仅仅是名称,而是整个(当前)外观对象(上面有你的 KVO)被替换。所以你宁愿观察 currentAppearance 而不是仅仅观察它的名字。
    【解决方案6】:

    但以防万一您确实想监控状态变化。我也知道有比上面所说的更好的方法来确定 lite/dark 模式,但我现在记得。

    // Monitor menu/dock theme changes...
    [[NSDistributedNotificationCenter defaultCenter] addObserver: self selector: @selector(themeChange:) name:@"AppleInterfaceThemeChangedNotification" object: NULL];
    
    //
    -(void) themeChange :(NSNotification *) notification
    {
        NSLog (@"%@", notification);
    }
    

    【讨论】:

      猜你喜欢
      • 2010-10-26
      • 2018-05-06
      • 1970-01-01
      • 2021-08-08
      • 2013-03-08
      • 1970-01-01
      • 2013-04-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多