前言
暗黑模式(Dark Mode)是iOS13推出的新功能,将传统的UIColor升级成dynamicColor。
TABAimated在v2.2.3实现了自动转换暗黑系列骨架屏。
本文讲解在v2.3.0版本的暗黑模式实现。
TABAnimated的骨架层是用CALayer实现的,但是CGColorRef并不能成为动态颜色,所以本文也将说明TABAnimated是如何实现动态的CGColorRef。
先睹为快
包括四种动画在内,多种应用场景,均以完美适配暗黑模式。
新增Api
属性 | 全局类 | 局部类 | 含义 |
---|---|---|---|
darkAnimatedColor | TABAnimated | TABViewAnimated | 暗黑模式骨架屏内容颜色 |
darkAnimatedBackgroundColor | TABAnimated | TABViewAnimated | 暗黑模式骨架屏背景颜色 |
开发者需要做什么?
原则上什么都不需要,但是背景颜色、内容颜色和各自产品有关,所以开放了对应属性。
通过gif,你发现了什么?
如下图,在已经切换暗黑模式后,进程卡片列表页面没有刷新,如果是UIColor系统会自动刷新,CGColorRef暂时没有找到办法处理。
结构图
暗黑模式实时性原理
我们知道只有UIView、UIViewController、UIPresentationController才能监听模式切换事件。
通过给予控制视图添加一个透明、size为(.1, .1)的哨兵视图,监听哨兵视图的traitCollection的变化, 再将该消息传递给暗黑模式管理者协议。
哨兵视图的管理者自然也是暗黑模式管理者。
暗黑模式管理者协议
为了进一步与生产层解耦,引入了TABAnimatedDarkModeManagerInterface
协议
// 绑定controlView
- (void)setControlView:(UIView *)controlView;
// 添加哨兵视图
- (void)addDarkModelSentryView;
/// 添加需要实时改变的view
- (void)addNeedChangeView:(UIView *)view;
// 释放
- (void)destroy;
1. setControlView
生产层在绑定controlView视图时,同时给予暗黑模式管理者绑定该controlView。
暗黑模式管理者需要controlView的原因:
获取controlView的traitCollection、tabAnimated,以提供给暗黑模式主体
2. addDarkModelSentryView
生产层绑定controlView后,给予controlView添加一个哨兵视图。 该哨兵视图用于监听traitCollection的变化
3. addNeedChangeView:
controlView视图的骨架屏主体不一定是其本身,比如UITableView是其上的cell。 该接口会将新生成的view加入到管理列表中
4. destroy
生命周期结束后,销毁不需要的对象
如何自定制骨架屏暗黑模式转换?
需要新建类,遵循自TABAnimatedDarkModeInterface
。
/// 暗黑模式转化协议主体,开发者可重写
/// TABAnimatedDarkModeImpl是该协议默认的实现,根据traitCollection、tabAnimated自动转化backgroundLayer、layers的属性
/// @param traitCollection 当前的traitCollection
/// @param tabAnimated 目标tabAnimated
/// @param backgroundLayer 目标背景layer
/// @param layers 目标layers
- (void)traitCollectionDidChange:(UITraitCollection *)traitCollection
tabAnimated:(TABViewAnimated *)tabAnimated
backgroundLayer:(TABComponentLayer *)backgroundLayer
layers:(NSArray <TABComponentLayer *> *)layers;
开发者根据入参所提供的traitCollection
来判断当前模式,
根据tabAnimated
获取控制视图的参数,最后根据自己的骨架、动画需求,自行调整暗黑风格。
模式禁用
apple本身是支持局部、全局禁用暗黑模式的,骨架屏同样会跟随你的禁用而禁用暗黑系骨架屏。所以对于骨架屏而言,除了配置颜色外,你不需要做任何其他多余的事情。
不能兼容的情况
后台卡片列表显示页面不能实时刷新。 解决方案:骨架层由CALayer换成UIView(这种方案不予采用)