一、适配Dark mode:颜色适配、图片适配
其实适配Dark模式,开发者主要从颜色和图片两个方面进行适配,我们不需要关心切换模式时改如何操作,这些都是系统帮我们实现,我们只需要做好适应两套模式的资源就好了
颜色适配:
系统自带
ios13之前UIColor只能表示一种颜色,而从ios13开始后UIColor可以表示一个动态的颜色,在Light Mode和Dark Mode可以分别设置不同的颜色
系统提供的一些动态颜色:
@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);@property (class, nonatomic, readonly) UIColor *systemGray3Color API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);@property (class, nonatomic, readonly) UIColor *systemGray4Color API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);@property (class, nonatomic, readonly) UIColor *systemGray5Color API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);@property (class, nonatomic, readonly) UIColor *systemGray6Color API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);@property (class, nonatomic, readonly) UIColor *labelColor API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);@property (class, nonatomic, readonly) UIColor *secondaryLabelColorAPI_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);@property (class, nonatomic, readonly) UIColor *tertiaryLabelColorAPI_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);@property (class, nonatomic, readonly) UIColor *quaternaryLabelColor API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);@property (class, nonatomic, readonly) UIColor *linkColorAPI_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);@property (class, nonatomic, readonly) UIColor *placeholderTextColor API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);@property (class, nonatomic, readonly) UIColor *separatorColorAPI_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);@property (class, nonatomic, readonly) UIColor *opaqueSeparatorColor API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);@property (class, nonatomic, readonly) UIColor *systemBackgroundColor API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);@property (class, nonatomic, readonly) UIColor *secondarySystemBackgroundColorAPI_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);@property (class, nonatomic, readonly) UIColor *tertiarySystemBackgroundColor API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);@property (class, nonatomic, readonly) UIColor *systemGroupedBackgroundColor API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);@property (class, nonatomic, readonly) UIColor *secondarySystemGroupedBackgroundColor API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);@property (class, nonatomic, readonly) UIColor *tertiarySystemGroupedBackgroundColor API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);@property (class, nonatomic, readonly) UIColor *systemFillColorAPI_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);@property (class, nonatomic, readonly) UIColor *secondarySystemFillColorAPI_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);@property (class, nonatomic, readonly) UIColor *tertiarySystemFillColor API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);@property (class, nonatomic, readonly) UIColor *quaternarySystemFillColorAPI_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
使用:
用户和ios13之前一样,使用系统提供的这些动态颜色,就不需要其他的适配操作。
[self.view setBackgroundColor:[UIColor systemBackgroundColor]];[self.titleLabel setTextColor:[UIColor labelColor]];[self.detailLabel setTextColor:[UIColor placeholderTextColor]];
自定义动态Color
在实际开发过程,系统提供的这些颜色还远远不够,因此我们需要创建更多的动态颜色,初始化动态UIColor方法:(一个是类方法,一个是实例方法)
+ (UIColor *)colorWithDynamicProvider:(UIColor * (^)(UITraitCollection *))dynamicProvider API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);- (UIColor *)initWithDynamicProvider:(UIColor * (^)(UITraitCollection *))dynamicProvider API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
这两个方法要求传一个block进去
当系统在LightMode和DarkMode之间相互切换时就会触发此回调
这个block会返回一个UITraitCollection类
我们需要使用其属性userInterfaceStyle,它是一个枚举类型,会告诉我们当前是LightMode还是DarkMode
使用
UIColor *dyColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull trainCollection) {if ([trainCollection userInterfaceStyle] == UIUserInterfaceStyleLight) {return [UIColor redColor];}else {return [UIColor greenColor];}}];[self.bgView setBackgroundColor:dyColor];
图片适配
图片资源需使用Assets.xcassets管理,点击选中图片,右边修改Appearances为,Any,Dark,然后会出现两种样式的图片,一个是Any Appearance(表示浅色模式下的图片),一个是Dark Appearance(表示深色模式下的图片),代码中也不需要做其他处理,改变手机模式,系统会自动变化。
注意:同一工程内多个Assets文件在打包后,就会生成一个Assets.car 文件,所以要保证Assets内资源文件的名字不能相同
二、获取当前模式(Light or Dark),以防做一些特殊处理
Trait Collections只会在 UIKit 体系中有效,所有与 CGColor 有关的设置,需要额外处理,业务中与之相关的主要有下列场景:
1. 阴影色值2. 富文本颜色3. CALayer 颜色
处理这些的时候,还是需要通过view.traitCollection先获得当前的用户界面模式,然后做出相应的调整。
示例:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {super.traitCollectionDidChange(previousTraitCollection)if #available(iOS 13.0, *) {if self.traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {// 处理相应的颜色button.border(radius: 20, width: 1.0, color: UIColor.color(lightColor: .blue, darkColor: .yellow))}}}
三、其他内容
1、监听模式切换
有时我们需要监听系统模式的变化,并作出响应
那么我们就需要在需要监听的viewController中,重写下列函数
// 注意:参数为变化前的traitCollection- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection;// 判断两个UITraitCollection对象是否不同- (BOOL)hasDifferentColorAppearanceComparedToTraitCollection:(UITraitCollection *)traitCollection;