写点什么

iOS 暗黑模式适配的完美解决方案

  • 2019-12-26
  • 本文字数:2695 字

    阅读完需:约 9 分钟

iOS暗黑模式适配的完美解决方案

一 背景

在 2019WWDC 的开场演讲中,苹果公布了即将推出的 iOS13 DarkMode 的新特性。此新特性不仅可以在夜晚保护视力,而且对于使用 OLED 的最新一代设备而言,也可以帮助用户节省电量消耗。不过此特性只支持 iOS13 以上的系统,为了给全系统所有用户最好的体验,研发出了一套皮肤主题框架,不仅可以全系统支持 DarkMode,还可以扩展多套皮肤主题;

二 皮肤主题框架的诞生 BDPAppearance

2.1 业务方使用方式

  • 目前系统所有控件及其 Color 属性和 Image 属性均已支持, 此处只列举两个例子:


// UIColorview.backgroundColor = BDPAppearanceColor(@"C1");
// UIImageimageV.image = BDPAppearanceImage(@"icon");
复制代码


业务方只需如上使用简单的 API 设置 Color 和 Image,即可实现主题换肤;

2.2 实现原理

先来看一下 BDPAppearance 设计方案的架构图



在项目初始化时,会先加载当前主题所使用的色值资源到内存中,相关控件通过 BDPAppearanceColor 用色名去找出对应主题下的色值,实例化出 UIColor 对象,并赋值给这些相关控件;


而内置的 UIImage 图片是存放在 Assets 中的,通过 BDPAppearanceImage 用图片名去加载当前主题下的 UIImage 对象即可;


  • UIColor 分类和 UIImage 分类

  • 可以看到图中,给 UIColor 分类添加了 ColorName 属性: 通过 BDPAppearanceColor 方式获取 UIColor 实例对象时,通过分类会记录当前 Color 对象所使用的色号名;

  • 同理,通过 BDPAppearanceImage 获取 UIImage 时,通过分类会记录当前 Image 对象所使用的图片名;

  • changeTheme 刷新主题

  • 每一个控件初始化添加到父视图的时候,在- (void)didMoveToSuperview 的时机将其添加到 NSHashTable 中, 点击切换主题时,通过 NSHashTable 拿到当前视图树上所有的视图控件,取出控件属性中的 UIColor 和 UIImage, 判断其 colorName 和 imageName 是否有值,有值即代表当前控件需要适配主题,则用此 colorName 或者 imageName 去加载当前主题的新色值和新图片,重新赋值给当前控件即完成了主题切换。

三 设计思路

设计此皮肤主题框架的原则:


业务方在现有业务的基础上以最低成本的方式进行适配:即只需更换获取颜色和图片的方式


那么在基于上述原则的前提下,我们应该如何在切换主题时,让所有的控件重新刷新主题呢?


在项目初期时,采用通知的方案:在 didMoveToSuperview 方法中给当前控件添加一个通知,当收到切换主题的通知时,则刷新当前控件的相关色值及图片;


但是在做性能测试时,发现采用通知方式初始化,不仅会有一定 CPU 消耗,同时也会增加初始化的耗时,视图层级越多,性能损耗越明显,所以放弃了此方案; 我们的目的其实就是可以让当前所有的视图可以触发刷新逻辑,最终采用了 NSHashTable 弱持有控件的方案;


两种方式性能测试数据:


以下数据均是测试 20 次以上取的平均值;


压力测试环境:视图层级 1w 个 View:


真机iphone5s初始化CPU消耗初始化耗时
正常50%3312ms
HashTable50%3341ms
Notification99%5115ms


由以上测试数据得出: 在上万个视图量级下, HashTable 性能是远远优于通知的方式

四 业界开源框架对比

以下是目前业界 GitHub 排名靠前的开源库对比:



同时对比 iOS13 系统 API 适配的方式:


UIColor *dynamicColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {        if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {            return [UIColor blackColor];        } else {            return [UIColor whiteColor];        }    }];
view.backgroundColor = dynamicColor;
复制代码


对比可以看出:BDPAppearance 使用方式是在保留 RD 开发习惯上的基础上最接近系统方式的,改动代码量是最小的;

五 客户端整体主题通信设计

百度 App 涉及到主题相关模块技术形态有:NA、H5、RN、HN 等,而在多种技术形态下主题模式又是如何通信呢?可以参考下边这张图:



如图所示:


  • 初始化 WKWebView 时采用的方案:在 UserAgent 中拼接 Key-Value 的方式初始化 WebView,达到在渲染时,最早时机拿到主题模式;

  • 主题变化通信采用的方案:数据通道和端能力,其本质是 JS 交互;

六 项目工程色值配置

  • 6.1 端内色值表的管理


整个百度 App 涉及近百个业务,组件近三百个,色号表的管理也显得尤为重要;


每个组件内部所使用到的色号仅仅是有限个, 如果所有组件用到的色值都统一放入一个色值表中管理,显然是不合理的,不利于解耦也更不利于组件化输出;那么最优的色值管理方式是什么呢?



如上图所示,组件各自管理自己所需的色值表,在项目编译时,会通过脚本将所有组件的色值表进行色值去重后,合并成一个总的色值表存储在 Themes 仓库下,然后初始化主题资源时读取 Themes 里边总的色值表即可; 此种处理方式则达到了组件间解耦的目的;


  • 6.2 Sketch 插件:ThemeMeasure


早期的开发中,UE 出图都是用的 Sketch 导出 HTML 格式标注图,而根据百度 App iOS 相关 CRD、FE 对实现技术的选型及配合要求,UE 需要提供并维护一套 NA+H5 色表,标注界面时标颜色的编号而非色值。为了达到此种效果,我们同期研发出了 Sketch 插件,可以在标注界面直接显示出色号,解决了 UE 标注色号的痛点,大大提高了效率; 如下图:



此插件共包含三种能力:


  • 1.多种便捷方式助力色号标注

  • Theme Measure 可以让设计师根据系统的推荐选择色号进行标注,还有贴心的批量标注向导,改变了过去设计师手动写色号进行标注的方式

  • 2.一键转换深色、夜间等主题

  • Theme Measure 能够让设计师一键将默认主题转换为深色、夜间或者其他主题(需要有相应的色值数据,正确的色号标注),改变了过去设计师需要手动逐一调整产出深色、夜间设计稿的方式,大幅提升设计师对多主题适配的工作效率及体验

  • 3.熟悉的标注导出方式,所有标注均在一处

  • 还是使用熟悉的工具导出标注,色号、布局、字号等标注均在同一个 HTML 文档内,改变了过去需要额外提供一份色号标注的方式,提升设计与研发的协同效率与体验


在整套皮肤主题机制下业务方仅仅花了不到两周的时间即完成了整个手百的主题适配,也从侧面证实此框架的优点:轻量级,使用成本低;


资源配置同时也支持云端下发,可动态新增多种主题;

七 支持自动跟随系统主题变化以及动画切换

00:00 / 00:00
    1.0x
    • 2.0x
    • 1.5x
    • 1.25x
    • 1.0x
    • 0.75x
    • 0.5x
    网页全屏
    全屏
    00:00

    八 总结

    本文主要从皮肤主题框架实现、色值表的管理以及配套工具链等方面详细的介绍了百度 App iOS 暗黑模式的适配,欢迎业内的朋友一起交流学习;


    本文转载自公众号百度 App 技术。


    原文链接


    https://mp.weixin.qq.com/s?__biz=MzUxMzk2ODI1NQ==&mid=2247483925&idx=1&sn=90a668648fa9c57e8b6a2adac0556bb7&chksm=f94c5305ce3bda13745d6fce34661dd3a5720958bae5376a34de8087b3d6da508649c752ac0c&scene=27#wechat_redirect


    2019-12-26 09:305508

    评论

    发布
    暂无评论
    发现更多内容

    WPF性能优化:性能分析工具

    EquatorCoco

    性能优化 服务器 WPF

    抢占市场先机:利用API商品数据接口激活您的数据资产

    Noah

    可用于智能客服的完全开源免费商用的知识库项目

    不在线第一只蜗牛

    架构 开源项目 技术栈 智能客服

    SD-WAN网络中,CPE设备的重要性与选择

    Ogcloud

    SD-WAN 企业网络 SD-WAN组网 SD-WAN服务商 SDWAN

    国际盛会 | 蔚蓝创造亮相KEY ENERGY 2024能源展

    科技热闻

    SD-WAN对云服务的影响

    Ogcloud

    SD-WAN 企业网络 SD-WAN组网 SD-WAN服务商 SDWAN

    互联网大厂面试题解析之大疆一面

    派大星

    Java 面试题 互联网大厂面试

    立即报名|3 月 8 日北京,稳定性 & 可观测沙龙来了!

    阿里巴巴云原生

    阿里云 容器 微服务 云原生

    商用AI PC,能帮企业带来什么?

    E科讯

    电商卖家如何利用API获取用户行为数据

    技术冰糖葫芦

    API 文档 API 策略

    探索基于Stable Diffusion的智能绘画大模型

    百度开发者中心

    人工智能 深度学习 图像 大模型

    用户使用433MHz无线模块时,出现偶尔无法收发数据的原因?

    Geek_ab1536

    多种方式获取淘宝商品详情数据,关键词搜索商品列表,店铺ID获取店铺所有商品,按图搜索获取商品详情数据

    Anzexi58

    API 文档

    J17资本合伙人SKY LAI确认出席Hack .Summit() 2024区块链开发者盛会

    TechubNews

    IDC 中搭建 Serverless 应用平台:通过 ACK One 和 Knative 玩转云资源

    阿里巴巴云原生

    阿里云 云原生 容器服务

    AI PC的风刮到企业里,看英特尔vPro怎么做到的

    E科讯

    SD-WAN技术:是挑战还是机遇?

    Ogcloud

    SD-WAN 企业网络 SD-WAN组网 SD-WAN服务商 SDWAN

    盘点6个最受欢迎的 Vue.js UI 库

    秃头小帅oi

    『双向奔赴,绿动未来』 ——能效电气2024新品发布会

    Geek_2d6073

    使用ConfuserEx代码混淆工具保护你的.NET应用程序

    EquatorCoco

    .net 开源 应用程序 混淆

    小红书笔记详情API入门指南

    技术冰糖葫芦

    API 文档

    Java面向对象之内部类的几类使用场景

    快乐非自愿限量之名

    Java 面向对象 开发语言 面向编程

    7万张H100打造的Open AI文生视频Sora功能原理详解|Sora注册全攻略

    蓝海大脑GPU

    比特币价格突破62000美元,近一个月涨幅超过40%

    区块链软件开发推广运营

    dapp开发 区块链开发 链游开发 NFT开发 公链开发

    2024年金三银四Java初中高级面试1000问,覆盖一线大厂各种面试痛点

    采菊东篱下

    编程 程序员 java面试

    什么是渗透测试?有哪些类型?

    小齐写代码

    对比传统主机,云主机贵吗?是否值得购买?

    一只扑棱蛾子

    云主机

    深度解析:Allure报告如何提升你的测试效率?

    测试人

    软件测试 自动化测试 测试开发

    跳槽必看MySQL索引:B+树原理揭秘与索引优缺点分析

    王中阳Go

    数据库 面试 金三银四 跳槽

    超越传统模式:商品企划系统如何助力鞋服品牌创新突围?

    第七在线

    长期有效!开放原子基金会联合龙蜥社区推出的「人人都可以参与开源」学习赛上线

    OpenAnolis小助手

    开源 操作系统 龙蜥社区 开放原子 人人都可以参与开源

    iOS暗黑模式适配的完美解决方案_架构_liushaohua_InfoQ精选文章