在iOS13中,苹果推出了新的暗黑模式,这就帮助我们在黑夜中使用不那么刺眼的应用。这个还是很符合大多数人在夜间玩手机的习惯。既然这样,那我们作为一个合格的开发,当然要及时拥抱变化,早日跟进这个功能。
DarkMode中有哪些适配方案呢?
1.将两种主题不同的素材直接存储在对象中,UIKit在主题变化时获取对应的素材进行更新展示。(例子:在Assets中设置不同的模式下的颜色和图片)
优点:工作量少,对原代码影响较少,开发省时省力
缺点:灵活性较差,如果是不同图的话会对包的体积有一定影响
2.通过接受主题变化的通知,在通知回调中做相应的适配工作
优点:高度自定义,灵活性强
缺点:代码量相对较多,适配工作量较大
下面分别对两种不同的放进行举例:
第一种方案:
1.1 颜色的处理
1.1.1 使用系统提供的UIKit的颜色(如labelColor、UIColor.secondaryLabelColor等)。这些颜色都内置了适配颜色,会根据不同主题自定切换适配。
if (@available(iOS 13.0, *)) {
_textLabel.textColor = UIColor.secondaryLabelColor;
}else {
_textLabel.textColor = [UIColor redColor];
}
1.1.2 创建动态颜色
通过对UIColor新增扩展类的方式添加一个方法,在设置时添加lightcolor和darkcolor。
之前还考虑过通过设置宏定义进行自动切换,只要在颜色的宏中修改就行,但是由于xcode没有检测到校验 回报多处警告,影响代码视觉体验,所以改为扩展。
#define kDarkMode @available(iOS 13.0, *) && UITraitCollection.currentTraitCollection.userInterfaceStyle == UIUserInterfaceStyleDark
#define Color_Background kDarkMode?[UIColor blackColor]:[UIColor whiteColor]
缺点:操作量较大
1.1.3 在assets中添加动态颜色资源
步骤二可以只设置any和dark 也可以设置any、light和dark
// 通过name方式直接取
UIColor *backgroundColor = [UIColor colorNamed:@"backgroundColor"];
1.2 图片的适配
1.2.1 在assets中添加动态图片资源
类似于颜色设置,使用方法还是和之前一样。
1.2.2 创建自己的动态图片
通过对UIImage新增扩展类的方式添加一个方法,在设置时添加lightcolor和darkcolor。类似于动态颜色的设置
1.2.3 网络图片
比如有这么一种场景:我浅色主题和深色主题下显示不同的图片,并且两张图片都不是本地的,都是从网络获取,实现思路大概是:先把两张图片下下来,在本地组装成动态图片
这个不常见,一般来说都是显示同一张图片。我们也可以通过sdwebimage进行设置。下载完图片后进行动态整合。
2.1 UITraitCollection
UITraitCollection是用来处理苹果手机的一些特性的存储和UI相关的配置 比如我修改了某些系统设置,如:改字体大小
+ (UITraitCollection *)traitCollectionWithPreferredContentSizeCategory:(UIContentSizeCategory)preferredContentSizeCategory API_AVAILABLE(ios(10.0));
@property (nonatomic, copy, readonly) UIContentSizeCategory preferredContentSizeCategory API_AVAILABLE(ios(10.0)); // unspecified: UIContentSizeCategoryUnspecified
关于主题模式切换的属性是我们本节关注的重点:
typedef NS_ENUM(NSInteger, UIUserInterfaceStyle) {
UIUserInterfaceStyleUnspecified,
UIUserInterfaceStyleLight,
UIUserInterfaceStyleDark,
} API_AVAILABLE(tvos(10.0)) API_AVAILABLE(ios(12.0)) API_UNAVAILABLE(watchos);
+ (UITraitCollection *)traitCollectionWithUserInterfaceStyle:(UIUserInterfaceStyle)userInterfaceStyle API_AVAILABLE(tvos(10.0)) API_AVAILABLE(ios(12.0)) API_UNAVAILABLE(watchos);
@property (nonatomic, readonly) UIUserInterfaceStyle userInterfaceStyle API_AVAILABLE(tvos(10.0)) API_AVAILABLE(ios(12.0)) API_UNAVAILABLE(watchos); // unspecified: UIUserInterfaceStyleUnspecified
2.2 通过子类重写traitCollectionDidChange这个方法来监听系统设置的一些属性变化
// 并不是每次系统调用traitCollectionDidChange:方法时,模式都有变化,也有可能是设备进行了旋转也会调用traitCollectionDidChange:方法,所以此时需要判断系统主题模式是否发生了改变,只要颜色发生改变后我们才对主题颜色进行修改。
- (void) traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
[super traitCollectionDidChange:previousTraitCollection];
UITraitCollection *traitCollection = [UITraitCollection currentTraitCollection];// 获取当前的TraitCollection
BOOL hasUserInterfaceStyleChanged = [previousTraitCollection hasDifferentColorAppearanceComparedToTraitCollection:traitCollection];
// 根据当前模式更新视图
}
补充功能:
1.如何全局关闭DarkMode?
1.在Info.plist 文件中,添加 key 为 User Interface Style 类型String。
2.将UIUserInterfaceStyle key 的值设置为 Light
2.如何只是单独几个页面关闭DarkMode?
// 在ios13系统下UIViewcontroller与UIView有一个新的属性 overrideUserInterfaceStyle 可以强制设置关闭暗黑模式的属性
typedef NS_ENUM(NSInteger, UIUserInterfaceStyle) {
UIUserInterfaceStyleUnspecified,
UIUserInterfaceStyleLight,
UIUserInterfaceStyleDark,
}
self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
3.系统主题更换之后会调用哪些方法?
在ViewController:
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
- (void)updateViewConstraints
- (void)viewWillLayoutSubviews
- (void)viewDidLayoutSubviews
在View里:
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
- (void)drawRect:(CGRect)rect
- (void)layoutSubviews
- (void)updateConstraints
- (void)tintColorDidChange
在UIPresentationController里:
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
- (void)containerViewWillLayoutSubviews
- (void)containerViewDidLayoutSubviews
4.启动图能根据不同的mode来展示不同的图片吗?
可以,我们可以像普通的图片那样针对深色模式设置另外的一张图片