如今的OS X app 必须要支持模式的切换,否则 review 过程中会被拒。从技术的角度,要适配 dark mode,主要是注意颜色和图片:
- 颜色:使用系统提供的“语义”颜色API,或者添加支持各个模式下的颜色集
- 图片:添加各个模式下的图片集
这里不从头讨论如何去实现,而是记录一次和模式切换相关的页面组建显示异常问题。
问题描述
App 使用了Split布局,左边区域的 NSViewController
中包含的组件有 NSTextField,
NSButton
和 NSTextView
。当从明亮或黑暗模式启动时,窗口内容显示正常。当从设置中,修改当前的外观时,发现 NSTextField
和 NSButton
中的文字和背景无法分辨,而 NSTextView
却正常显示。
排查过程
第一反应是打开 storyboard , 选中 ViewController,然后点击下方的 View as
。此时,发现单独 dark 或 light appearance,页面正常显示。同时,确认了每个控件使用的颜色都是 semantic color API。
接下来,重启了系统。因为刚好因为系统空间不够,大刀阔斧地删除了一些文件,包括 Developer
下的内容。当然,重启后,并没有解决。
下一步,决定在相关的 ViewController 中,重载 viewWillLayout
,在其中显式地为控件颜色赋值,但仍然无果:窗口内的控件依然不能正确显示。
接着,打算使用 Xcode 的 “Debug View Hierarchy”,谁知一点击,Xcode 就 crash......
为了好好地静一静,又看了下文档 Supporting Dark Mode in Your Interface,看着看着意识到控件的appearance通常是一次继承的:
NSApp->NSWindow->NSViewController->NSView
那是否有可能是上级 ViewController 或者 Window 中进行了某些操作呢?一查看,如果发现在某个父级 ViewController 中,用如下方式修改了 view 背景色:
self.view.wantsLayer = true
self.view.layer?.backgroundColor = NSColor.lightGray.cgColor
注意这种通过修改 CALayer 的方式即使使用 semantic color,如 controlBackgroundColor 也不会起作用。最后,将上述部分删除。
最后,想强调的是, NSViewController 和 UIViewController 不同,修改对应的 view 的背景色在 Cocoa 上,建议新建 NSView
,在 updateLayer
中进行修改, 如:
override func updateLayer() {
self.layer?.backgroundColor = NSColor.textBackgroundColor.cgColor
// Other updates.
}
Comments