分享实时检测 macOS 菜单栏颜色的方法

2020-11-26 16:20:12 +08:00
 quietjosen

macOS 菜单栏颜色历史是这样的:

这有什么问题呢?

对于我的几款应用 iText 、iPic 、iTimer,要在菜单栏上绘制进度条,就需要知道用什么前景色。不然,如果在暗色的菜单栏上用黑色绘制,就什么都看不出来了。

之前,这很容易,只要检测系统主题即可。而如上所述,macOS 11 后变得麻烦了,怎么知道菜单栏当前是什么颜色呢?

网上一通搜索(恩,面向 Google 编程),最后在 StackOverflow 上找到 这篇帖子,算是找到了优雅的解决方案:检测菜单栏图标按钮的样式

let appearanceName = statusItem?.button?.effectiveAppearance.name.rawValue.lowercased()
let isDarkMode = appearanceName?.contains("dark")

其实,找到技术方案后,感觉很简单,也很开心。而难的是解决问题的思路,以及搜索、寻求帮助的能力。

3340 次点击
所在节点    程序员
24 条回复
Cavolo
2020-11-26 19:35:45 +08:00
然而 Adobe 并不想解决这个问题,现在菜单栏里只有 Creative Cloud 的配色我行我素
archean
2020-11-26 20:01:17 +08:00
iPic 付费用户路过赞一下,App 体验很好,应该跟作者追求细节的精神是分不开的。
ysc3839
2020-11-26 20:49:39 +08:00
真的要检测系统颜色吗?前段时间我研究了下 ClashX 的状态栏图标,发现并没有检测系统是什么颜色。
同时在系统设置中切换主题的时候,状态栏也有颜色过渡的效果,如果检测颜色的话也实现不了吧?
mxalbert1996
2020-11-26 22:22:26 +08:00
@ysc3839 只显示一个图标当然不用,楼主也说了是要自己绘制进度条
ysc3839
2020-11-26 23:04:07 +08:00
@mxalbert1996 但是 ClashX 还显示了网速呀。
ysc3839
2020-11-26 23:06:56 +08:00
@mxalbert1996 而且既然只显示一个图标不需要自行处理,那不就意味着系统会自动根据当前颜色再次进行处理,不需要应用开发者操心吗?为什么别的内容反而要自行处理了呢?这设计不符合逻辑吧。
yov123456
2020-11-26 23:12:30 +08:00
简单的话可以像 clashx 那样生成 tint image 的方式 不过之后 clashx 也会换成单一 view+layer 形式去绘制减小生成图片的开销。(为啥要单一 view 呢 之前实验有 subview 的时候多显示器 第二个显示器上会显示异常。
@ysc3839
quietjosen
2020-11-26 23:38:10 +08:00
@Cavolo 人家大牌啊;想起我还买了点 Adobe 股票,这两天还在涨…
quietjosen
2020-11-26 23:38:37 +08:00
@archean 谢谢支持,我也很开心自己的用心能被感受到 🤝
quietjosen
2020-11-26 23:40:13 +08:00
@ysc3839 如果只是图标的话,设置 NSImage.isTemplate = true 即可,相当于把图片变成仅透明度通道,然后由系统决定具体是白色还是黑色。自己在 NSView 中绘制的话,暂时没找到自动的办法,只能自己指定白色还是黑色。
quietjosen
2020-11-26 23:50:07 +08:00
@ysc3839 谢谢介绍 ClashX 。我看了相关代码( StatusItemView.swift ),他的做法是在 NSView 上绘制,然后根据 NSView 生成 NSImage,并设置为 NSStatusItem 的 image 。我测试了文字确实是能适应不同菜单栏颜色的(不过颜色值或透明度不是太完美),明天我再研究下。
mxalbert1996
2020-11-27 12:06:49 +08:00
@ysc3839
使用系统默认的样式可以省很多事并且兼容性好但是会有限制(有些事情做不了),如果想要更高的可定制性就必须舍弃系统提供的一些便利自己处理各种问题,这在开发界是常识。
就好比 Android 的通知,使用系统默认样式的话可以适配任意系统版本和暗黑模式,但使用自定义样式但在高版本系统上看起来很丑或者没适配暗黑模式的应用多得是。
ysc3839
2020-11-27 12:28:39 +08:00
@mxalbert1996 我是以为系统并没有提供自己指定颜色的方法,macOS 提供的这种集成度比较高的 API,限制某些功能来换取开发上的便利性也不奇怪。
quietjosen
2020-11-27 15:27:20 +08:00
@mxalbert1996 恩,你说的是。具体至 macOS 菜单栏,就是自己绘制,可以绘制任意内容。但问题是,有可能前景色和菜单栏背景色完全一样,导致用户完全看不到内容。使用系统的方案则差不多相反。
quietjosen
2020-11-27 15:28:32 +08:00
@ysc3839 如果使用图标方案,并不能指定颜色,只能是提供一个透明的图,则系统渲染。

事实上,macOS 菜单栏的前景色,到目前为止,也只有白色和黑色,无论桌面背景图片及菜单栏是什么颜色。
yov123456
2020-11-28 14:41:01 +08:00
@quietjosen 今天试验了一下 可能得继续使用 clashx 这种截图的方法才能完美适配多个显示器。现在 big sur 上连接两个显示器的时候会因为背景不同同时展示 light/dark 两种样式的 toolbar 。view 只有一个可能没法两个显示器上都同时适配? 我试了 eul 和 istatmenu 在这种情况下都表现不好。有什么好的解决方案一起研究研究~
quietjosen
2020-11-29 22:58:44 +08:00
@yov123456 你这样例子太狠了。除非 macOS 有接口返回菜单栏指定位置的颜色值,否则是无解的,只能乖乖用图片的方式。
quietjosen
2020-12-01 07:18:35 +08:00
@yov123456 我用 iText (开发版)测试了本机 + 外接显示器,不同的桌面图片,配置成一个白色、一个黑色菜单栏。当两个桌面分别获得焦点时,iText 可以获得当前菜单栏图标的正确 Appearance,进而可以正确的显示前景色,进度条完美。
yov123456
2020-12-01 07:39:57 +08:00
@quietjosen 但是另一个桌面显示的就不对了吧🤣🤣
quietjosen
2020-12-01 09:11:19 +08:00
@yov123456 你是意思是,当前在一个显示器上展示正确、另一个不正确?
其实,我根本就没注意这一点,因为 iText 的进度条很短,当眼睛在一个显示器上时,不太会去看另外一个。
另外,如果使用 Bartender 时,另一个显示器的菜单栏图标是隐藏的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/729535

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX