Mac开发跬步积累(五): Dark Mode下适配你的UI界面

图片来自Apple官方

macOS 10.14中,苹果在系统本身样式(Light (aqua) appearance
)基础上推出了暗黑模式(dark appearance),这种模式下可以更突出显示应用窗口中的内容,让用户的关注焦点聚集在App本身的视图中以便获取更佳的视觉体验.关于AppKit中的系统视图,苹果默认已经进行了暗黑模式适配升级,但对于许多自定义的View,还是需要我们花一点点时间处理的.

0x00: 关于 NSAppearance

macOS 10.9+ 的时候,苹果就提供了NSAppearance这个类来协助AppKit管理App的UI控件. NSAppearance决定着AppKit如何渲染每个UI控件的效果,尤其是与颜色或者图片相关的部分.

  • App启动后会获取系统当前样式(Light Appearance 或者Dark Appearance).
  • NSWindow会继承App的appearance效果;
  • NSView会继承其父类或者NSWindowappearance效果;
  • 开发者可以设置App的整体或者部分appearance效果;
  • Appkit绘制UI控件时,会自动将当前的appearance赋值给控件的appearance(在当前线程中进行);
  • NSAppearance会影响 系统字体(font),颜色(color),文本(text),图片(image)的相关绘制路径(draw path)进而影响显示效果.

0x01: 颜色适配(NSColor)

当用户切换Light / Dark Appearance时,UI控件的颜色有着明显不同的效果.在macOS 10.14之前我们对于一个控件的颜色值经常使用硬编码方式,因此当appearance变化时,这些硬编码的色值就难以适应了.

Appearance变化时,关于NSColor的适配苹果官方给出两种简单并且易于实现的方案:

  1. 使用带有语义的Color:
    那么问题来了,到底什么是带有语义的Color呢? 看一下苹果官方的原文:
    Semantic colors let you specify colors based on their intended usage, rather than on the actual color.
    简单的说就是根据使用场景来描述颜色,而不使用确切的值来描述颜色.
    我们以一个Label 的例子来看一下代码与效果:
    设置labelColor

运行效果:


LabelColor 在Dark 和Light 模式下的效果

系统提供的语义Color可以参考苹果开发者文档中的:UI Element Colors
例如Label相关的有:labelColor , secondaryLabelColor,tertiaryLabelColor,quaternaryLabelColor等.

除了这些语义Color之外,系统还提供了一下可适配的Color,通常都以system+颜色方式命名.例子如下:

         NSColor.systemRed
         NSColor.systemBlue
         NSColor.systemGray
         NSColor.systemPink
  1. 使用Assets Color:(推荐)
    更多时候我们希望能够有更多自己可以定义的颜色,这时系统提供的语义Color就会显得不够用,这时我们可以使用Assets Color,具体操作请参考下图示例:
    Assets Color 设置

    Appearance 说明

    代码调用Assets Color: "Color"是在Assets 中创建的颜色名称
    调用Assets Color

    运行效果:
    Assets Color 运行效果

0x02: 图片适配(NSImage)

App图片是非常重要的UI资源,为了在合适的Appearance下显示正确的图片,主要有下面的三种方式.

  1. Image Assets
    使用Assets ImageAssets Color非常相似,具体请参考操作图例:
    Assets Image Set

Assets Image 的适配场景(即当下面场景变化时,会Appkit会自动调整Image进行适配):

  • Screen resolution(屏幕分辨率):
    Appkit会自动根据当前屏幕的解析度选取最佳的image进行显示
  • Light and dark appearances (Appearance切换):
    Any Appearance中的图片会适配macOS全版本,Light和Dark 仅适用macOS10.14之后的版本
  • High contrast (高对比度):
    使图片与周边的内容对比根据突出,仅能用于macOS10.14+之后的版本
  1. Template Images
    使用模版图片也是一种常用的适配解决方案,典型的案例就是设置控件的icon(比如一个播放或者暂停的按钮).这种方法需要配合使用图片编辑软件(项目中的话通常就是UI设计师来处理)制作图片模版,具体使用仅需两个步骤即可:
  • UI设计师需要根据场景设计图片,但需要遵守如下规则:
    template 设置规则

    需要忽略的部分使用透明背景
    需要显示的部分使用黑色或者部分透明的黑色
  • 设置图片的渲染模式为Template:
    设置图片渲染模式
  1. Drawing Handler
    使用NSImageinit(size:flipped:drawingHandler:)方法可以让Appkit根据appearance变化时自动调用drawingHandler中的代码进行图片创建,从而实现适配效果;

0x03: 自定义View 适配(NSView)

当改变当前的appearance时,AppKit会自动调用NSView的下面几个方法(根据情况调用)

  • updateLayer()
  • draw(_:)
  • layout()
  • updateConstraints()
    这样我们就有机会在变更appearance时,通过重载上面的方法来实现自定义view的UI适配工作,示例代码如下:
override func updateLayer() {
   self.layer?.backgroundColor = NSColor.textBackgroundColor.cgColor

   // Other updates.
}

注意点!!!
NSColor会立刻生效,但CGColor需要App再次启动才会生效!

0x04: 定制App的appearance(NSApp)

  • 设置NSView或者NSWindowappearance:
    NSView Appearance

    注意点!!!
    Appearance是存在继承关系的:NSApp->NSWindow->NSView
  • 通过代码方式设置NSViewappearance:
class MyContentView : NSView {
  func adoptAquaAppearance()
      self.appearance = NSAppearance(named: .aqua)
   }
}
  • 设置NSAppAppearance:
  NSApp.appearance = NSAppearance(named: .darkAqua)

0x05: Visual Effect View

关于NSVisualEffectViewAppearance适配,苹果官方建议采用根据使用明确场景语义枚举.例如在一个popOver的窗口中,推荐使用NSVisualEffectView.Material.popover,这样系统就根据appearance变化自动选择合适的效果了.同时系统也废弃了如下的枚举:

  • NSVisualEffectView.Material.light Deprecated
  • NSVisualEffectView.Material.dark Deprecated
  • NSVisualEffectView.Material.mediumLight Deprecated
  • NSVisualEffectView.Material.ultraDark Deprecated

0x06: 当appearance 切换时,应避免耗时操作

当切换系统的Appearance时,AppKit会同时更新UI控件,这部分工作通常都是自动完成的.但有时也会调用开发者编写的代码,例如你使用了NSImagedraw handler 方式创建图片对象,又或者使用了KVO监听一个视图或者窗口的effectiveAppearance属性,因此请需要注意下面几点:

  • 尽可能快的更新UI;
  • 不要执行与appearance变更无关的任务;
  • appearance变化时AppKit会自动添加过渡效果动画,但如果你的更新UI代码任务过重,AppKit将会丢弃过渡效果动画!

0x07: one more thing

为了考虑兼容macOS10.14之前的App版本,但又想支持Dark Appearance的效果,那么可以在Info.plist中添加 NSRequiresAquaSystemAppearancekey,并设置值为true即可.
这样做的前提是要保证App在macOS10.14的Dark Mode下可以正常适配UI效果~.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,295评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,928评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,682评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,209评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,237评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,965评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,586评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,487评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,016评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,136评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,271评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,948评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,619评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,139评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,252评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,598评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,267评论 2 358

推荐阅读更多精彩内容

  • 1:在线工具 2:免费图片空间 niupic 、picb.cc 3:内网映射工具NATAPP 4:在线版B-Tr...
    FFriday阅读 136评论 0 0
  • 灵魂导师-张杰,你的歌声是我不懈奋进的力量,是我迷茫时最温暖的港湾,我的未来不是梦,好久没听了,如今再听真的太多感...
    百面书生24阅读 209评论 0 0
  • 今天,该我上班。下午去接儿子,顺便给他带点好吃的。去的有点晚,我不确定他是否回家,只好打电话问邻居,她也不在家...
    二年级十班彭朝阳妈妈阅读 199评论 0 1
  • 大家千万不要以为那照片中的树叫红杉树,红杉树只是我对她亲切的叫法。就像你喜欢一个人就会给他起个小名,叫他的爱称一样...
    孔雀东南飞飞阅读 944评论 1 18