V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
quietjosen
V2EX  ›  程序员

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

  •  
  •   quietjosen ·
    atjason · 2020-11-26 16:20:12 +08:00 · 3346 次点击
    这是一个创建于 1458 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    • macOS 10.14 Mojave 之前,只有白色。
    • macOS 10.14 Mojave 开始支持暗色模式,于是有白与黑。
    • macOS 11 Big Sur 之后,菜单栏的颜色又同时受桌面图片的影响。比如,即使当前是暗色模式,如果桌面背景是白色,菜单栏也是黑色的。

    这有什么问题呢?

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

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

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

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

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

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

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

    https://tva1.sinaimg.cn/large/0081Kckwly1gl8h23m5lvj30a60be0z5.jpg
    yov123456
        23
    yov123456  
       2020-12-01 17:50:32 +08:00 via iPhone
    @quietjosen 是的 clashx 现在也是这么做的…感觉只有这样了
    yov123456
        24
    yov123456  
       2020-12-01 17:51:05 +08:00 via iPhone
    之前还想着优化一下变成 view 来节约性能 走不通啊。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1074 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 19:06 · PVG 03:06 · LAX 11:06 · JFK 14:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.