全局关闭DarkMode
这是目前采取的方案,让APP始终保持LightMode,在info.plsit文件中,添加UIUserInterfaceStyle , 值为Light 。
我们要适配DarkMode,需要将UIUserInterfaceStyle删除。
UIColor
iOS13之前 UIColor只能表示一种颜色,从iOS13开始UIColor是一个动态的颜色,在LightMode和DarkMode可以分别设置不同的颜色。
1.首先系统为我们提供了一些动态颜色,使用这种动态颜色,系统直接替我们完成了适配工作。但是系统提供的颜色不符合APP的设计规范的话,一般情况下我们用不到。
@property (class, nonatomic, readonly) UIColor *systemBrownColor API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *systemIndigoColor API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *systemGray2Color API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
...
...
2.自定义动态UIColor
UIColor *textDyColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleLight) {
return [UIColor JMEColorWithHexString:@"#2E2D2D"];
} else {
return [UIColor yellowColor];
}
}];
_nameLabel.textColor = textDyColor;
这样当系统切换DarkMode/LightMode时,会回调(UIColor * (^)(UITraitCollection *traitCollection))dynamicProvider这个block,自动为我们更新颜色。
图片资源
JDME目前使用了Assets.xcassets来管理图片,适配DarkMode还是比较方便的。
打开Assets.xcassets,设置Appearance为 Any,Dark
将设计师提供的DarkMode素材图片拖入对应的位置,还像往常一样使用图片就可以了。
[_logoImage setImage:[UIImage imageNamed:@"icon_logo"]];
获取当前模式(LightMode/DarkMode)
上面提到的颜色和图片,都是由系统来帮我们完成切换的。但是在某些场景下,我们需要根据当前的模式,来做一些其他的适配需求。
我们可以在 UIViewController 或者 UIView 中调用traitCollection.userInterfaceStyle来获取当前视图的模式。
if (@available(iOS 13.0, *)) {
UIUserInterfaceStyle style = self.traitCollection.userInterfaceStyle;
if (style == UIUserInterfaceStyleLight) {
///TODO:...
} else {
///TODO:...
}
}
userInterfaceStyle 是iOS12出现的,但是暗黑模式是iOS13才有的,所以为了避免不必要的影响,我们还是加上@available(iOS 13.0, *) 的判断条件。
适当的时候我们可能还需要在drawRect/layoutSubViews等方法中,根据当前的模式重新设定一些色值。
监听模式的切换(LightMode/DarkMode)
无论是LightMode还是DarkMode,用户都可以切出APP,或者下拉控制中心浮层来随意切换,所以我们还需要监听模式的切换。
在 UIView 和 UIViewController 中,当模式切换时,就会触发下面这个方法
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
if (@available(iOS 13.0, *)) {
if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection]) {
///TODO:...
}
} else {
// Fallback on earlier versions
}
}
CGColor
对于CGColor,我们可以使用上述的获取当前模式和监听模式的方式来处理不同的CGColor。
Status Bar
之前 Status Bar 有两种状态,default 和 lightContent
现在 Status Bar 有三种状态,default, darkContent 和 lightContent
现在的 darkContent 对应之前的 default,现在的 default 会根据情况自动选择 darkContent 和 lightContent
JDME中设置状态栏颜色的地方有很多,这个还得具体情况具体分析。
UIActivityIndicatorView
之前的 UIActivityIndicatorView 有三种 style 分别为 whiteLarge, white 和 gray,现在全部废弃。
增加两种 style 分别为 medium 和 large,指示器颜色用 color 属性修改。
NSAttributedString
对于UILabel、UITextField、UITextView,在设置NSAttributedString时也要考虑适配Dark Mode
Storyboard/Xib
xib中,系统提供了使用colorAssets的方式,类似于图片,但是为了兼容低版本,我们还是需要手动代码来更改颜色,单独适配。
第三方模块:
H5 App (WKWebview)
具体由第三方应用做适配
SDK
需要相关团队做适配。
Flutter Module (Calendar/Login)
尽管 Flutter 在 MaterialApp中提供了theme 与 darkTheme两个入口让我们设置两种模式下的颜色及文字样式,但是还是需要注意一些细节,提供的样式是否与设计师的要求一致。
注意,Flutter 1.9.1的版本并没有适配iOS 13 Status Bar新增的UIStatusBarStyleDarkContent 。
ReactNative Module (JoySpace)
RN团队需要做适配。
对于设计师
设计师需要提供一套设计规范,作为底层颜色自动转换的映射表。我们使用系统提供的方案,可以很快做到颜色转换来适配暗黑色模式。但是,有些颜色是需要单独配置的,不能完全遵循底层的颜色转换,所以,每个页面都需要设计人员验收,自动转换的颜色是否符合整体页面的UI效果,如果有变动,尽量给出一份暗黑模式的标注图,然后我们再做单独配置。所以,对于设计人员和开发需要适配的工作量还是蛮大的。