欢迎登录个人我的网站: www.sketchk.xyzswift
Dark Mode 做为 iOS 13 的新特性之一,为 App 的呈现方式带来了更多的可能,但也给开发者带来了大量的适配工做。app
在适配 Dark Mode 的过程当中,开发者只须要思考清楚下面三个问题便可:ide
在 iOS 13 中,因为 UIView 和 UIViewController 这些基类已经遵循了 UITraitEnvironment 协议,咱们能够经过 UITraitCollection 判断 App 当前的 Apparance 状态。代码以下所示:网站
Swift 的代码以下:ui
let isDark = UITraitCollection.current.userInterfaceStyle == .dark
let realColor = UIColor.systemBackground.resolvedColor(with: traitCollection)
let realImage = UIImage(named: "Header")?.imageAsset?.image(with: traitCollection)
复制代码
Objective-C 的代码以下:spa
BOOL isDark = [UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark? YES: NO;
UIColor *realColor = [[UIColor systemBackgroundColor] resolvedColorWithTraitCollection:traitCollection];
UIImage *image = [[[UIImage imageNamed:@"Header"] imageAsset] imageWithConfiguration:traitCollection]
复制代码
须要注意的是,上方代码中咱们调用了 [UITraitCollection currentTraitCollection],但 UITraitCollection 并非以单例的方式存在,每一个 view 和 ViewController 都有一个属于自身的 UITraitCollection 类型的属性。设计
因此咱们也彻底能够经过 traitCollection.
或者 self.traitCollection
的方式获取此属性,3d
不过,也不是全部方法执行前,UIKit 都会帮咱们作把 UITraitCollection.current 设置为 self.traitCollection,只有在如下这些方法中会执行此操做:code
UIView | UIViewController | UIPresentationController |
---|---|---|
draw() | ||
layoutSubview() | viewWillLayoutSubviews() viewDidLayoutSubviews() |
containerViewWillLayoutSubviews() containerViewDidLayoutSubviews() |
traitCollectionDidChange() tintColorDidChange() |
traitCollectionDidChange() | traitCollectionDidChange() |
在实际写代码前,咱们还需更深入的理解适配 Dark Mode 这项工做背后的含义。cdn
虽然 Apple 给出了了许多好用的 API 帮助开发者迅速完成 Dark Mode 的适配,但这是你应该用的 API 么?例如系统给出了 systemBlue
, systemGray
等 API 到底意味着什么?
这里须要明确的是 systemBlue
这些 API 本质上在 Apple 的 Human Interface Guidelines 下制定的 Dark Mode 配色,并不表明这些配色就应该无脑的用在你的 App 上。
Apple 原生的 App 大多数是以白色或浅色系为基调,因此在此设计规范下,它提供的 API 下能够很好的作 Light Mode 和 Dark Mode 的切换,且 App 的视觉效果十分惊艳。
但若是你的 App 不是浅色系,若是像淘宝的橙色系,饿了么的蓝色系,甚至多闪的暗色系,他们若是直接用 Apple 的设计规范,从视觉体验上来讲,可能就显得有点不那么匹配了,并且 Apple 提供给你的这些 API 就显得有点多余。
因此在动手前你须要明确本身的需求,Apple 提供的这些设计规范是否符合 App 当前的调性,或者设计师和你的预期么?
若是是的,请大胆的使用 Apple 提供的 API 吧。关于这些 API 表明的样式彻底能够在 Apple 提供的 Human Interface Guidelines 和 Resource 中找到。
若是不是,请结合自身 App 的设计规范,抽象出一个中间层或者 SDK 来定义这些变化。
与 Dark Mode 相关的 API 有如下几个特色
UIActivityIndicatorView
的 style 属性从 gray
, white
, whiteLarge
变成了 large
和 medium
,UIStatusBar
的 style 属性从 default
和 lightContent
变成了 default
和 lightContent
和 darkContent
,其中 default
样式会根据当前的模式展现不一样的颜色这里的核心问题就是在 Appearance 切换后,哪些元素须要适配?
大部分人的第一直觉会认为是控件颜色,例如控件的背景色和控件的内容颜色,那还有别的元素么?
显然是有的,须要考虑的类型大致有两种,一种是图片素材,一种是模糊效果,咱们先简单阐述下这两个元素适配的必要性
图片素材的适配必要性显而易见,例如 tab bar 或者 navigation bar 里的 icon,在切换为 dark mode 后,那些原先就是黑色的 icon 在 dark mode 下会变得难以辨识。
若是说图片素材要解决的是辨识度问题,那么模糊效果须要解决的就是协调性问题,若是在 dark 模式下,模糊效果总体过于泛白就会显得有些格格不入,进而影响用户体验。
上面说明了必要性,咱们来讲说针对不一样元素的适配方案
若是系统颜色符合你的预期,经过下面的语句就能够实现 dark mode 的适配
self.view.backgroundColor = .systemBackground
复制代码
若是系统颜色不符合你的预期,经过下面的语句来实现 dark mode 的适配
self.textView.textColor = .myDynamicColor
extension UIColor {
class var myDynamicColor: UIColor {
get {
.init(dynamicProvider: { (traitCollection) -> UIColor in
if traitCollection.userInterfaceStyle == .dark {
return UIColor(displayP3Red: 0, green: 0, blue: 0, alpha: 1)
} else {
return UIColor(displayP3Red: 255, green: 255, blue: 255, alpha: 1)
}
})
}
}
}
复制代码
一般状态下,App 内的组件都是直接使用系统提供的 UIBlurEffectView 组件,经过下面的代码就能够快速完成 Dark Mode 的匹配,固然 style 里面的 system
开头的枚举值须要你根据自身的状况进行选择。
let blurView = UIVisualEffectView(effect: UIBlurEffect.init(style: .systemMaterial))
复制代码
若是你的模糊控件是自行开发的,那么你就须要根据自身 App 的设计规范从新开发一套 API 来知足使用。
咱们能够利用 xcassets 中为图片控件新增的 Apperance 属性,分别设置两种模式下所使用到的图片,例如在深色模式下展现日落的照片,而在普通模式下展现日出的照片。
恭喜你,至此你已经掌握了适配 Dark Mode 的全部基本知识点,剩下须要作的就是实战了。
若是你还想更深刻理解 dark mode 的相关信息,能够观看 WWDC 2019 Session 214: Implementing Dark Mode on iOS