暗黑模式适配

news/2024/11/24 11:42:04/

为了跟上友商的步伐,我们最近也上了暗黑模式。

结果:
1.网页兼容安卓10及其以上,由网页前端处理;
2.原生页面设置浅色和深色都有效。但是跟随系统的话,由于安卓系统10以下没有设置暗黑模式的入口,所以设置跟随系统后一直是浅色。
3.由于App由原生 View 和 Compose View 实现的,所以需要两套 UI 都要实现暗黑模式;
4.在处理 UI 基础 library 和业务 library 实现了暗黑模式的同时,需要处理没有暗黑模式要求的 App ,直接设置为浅色模式即可

遇到的问题:

  1. 无法兼容 android 10 以下的系统
  2. 修改暗黑模式后,部分颜色没有更新
  3. 修改暗黑模式后,跟随系统部分手机不生效
  4. 系统暗黑模式修改后,无论当前处理什么模式,所有 Activity 都会 reCreate

问题1:无法兼容 android 10 以下的系统
1.1 第三方库 Android-skin-support
开始之前也在网上查过相关的实现,类似功能就是换肤。
但是,我们做的是暗黑模式,包括:浅色,深色,跟随系统。
其中浅色和深色比较好实现,但是跟随系统的话,换肤功能就不方便实现了。用的最多的就是 Android-skin-support 这个库,实现起来也不容易,当然自己实现也挺麻烦。
未处理的 issue 接近三位数了,最后一次维护是3年前,慎用。
插件换肤,我们除了需要在国内各大应用市场上架外,还需要在 google play 上架,皮肤颜色相关的资源打包成一个 .apk 文件放在住工程内就不符合 google play 的上架规范。
1.2 我们的用户手机系统低于 android 10 的用户占比不多,小公司也那么多人手去做这种投入产出比较低的事情
1.3 我们的 App 有传统 View 和 Compose View 的实现,接入可能产生其他问题

问题2:修改暗黑模式后,部分颜色没有更新
2.1 所有 View 相关的页面,包括 View 和 Compose View 混合的页面的 Activity 必须继承自 AppCompatActivity。单纯的 Compose 页面没有这个要求。
2.2 除非特殊页面,比如分享页外,所有地方的颜色都不能直接硬编码。所有颜色均使用 xml 中定义的两套颜色,或使用 Compose 调色板中指定的主题颜色。
2.3 View 设置颜色不能直接使用 application 的 Context 作为上下文去获取颜色,需使用 Activity 的 Context 去获取上下问。

问题3: 修改暗黑模式后,跟随系统部分手机不生效
这个手查了很久才解决的问题,起初发现是在 debug 版本和 beta 版本之间的差异问题,在 debug 版本中不存在这个问题。最后发现是由于 debug 版本中关闭了多语言的功能,为了提升编译速度,禁止了多语言相关的实现。
最后发现是在对多语言处理的时候,导致了 Configuration 中的 uiMode 出现了问题。然后解决办法也就很清晰了:

override fun attachBaseContext(context: Context?) {super.attachBaseContext(InjectUtils.updateLocalConfig(context))}override fun onConfigurationChanged(newConfig: Configuration) {super.onConfigurationChanged(newConfig)InjectUtils.onConfigChange(newConfig) // 再次矫正 UI_MODE}
// InjectUtils.kt
fun updateLocalConfig(context: Context?): Context? {return context?.let {val languageContext = setLocalLanguage(it)setLocalDarkMode(languageContext)}}
private fun setLocalDarkMode(context: Context?): Context? {val res = context?.resourcesval config = Configuration(res?.configuration)config.uiMode = DarkModeUtils.getCurrentUIMode(config.uiMode)return context?.createConfigurationContext(config)}
// DarkModeUtils.kt 根据当前模式还原正确的 UI_MODE 参数
fun getCurrentUIMode(uiMode: Int) = when (getCurrentMode()) {AppearanceMode.DAY -> Configuration.UI_MODE_NIGHT_NOAppearanceMode.NIGHT -> Configuration.UI_MODE_NIGHT_YESelse -> Configuration.UI_MODE_NIGHT_UNDEFINED}.let {uiMode and Configuration.UI_MODE_NIGHT_MASK.inv() or it}

问题四:
暂时无法解决,看起来是系统处理的。
4.1 对于重要的页面,进行数据保存: onSaveInstanceState
4.2 说服老板


http://www.ppmy.cn/news/27305.html

相关文章

MySQL-redo log和undo log

什么是事务 事务是由数据库中一系列的访问和更新组成的逻辑执行单元 事务的逻辑单元中可以是一条SQL语句,也可以是一段SQL逻辑,这段逻辑要么全部执行成功,要么全部执行失败 举个最常见的例子,你早上出去买早餐,支付…

Julia 数据类型

在编程语言中,都有基本的数学运算和科学计算,它们常用的数据类型为整数和浮点数。 另外还有一个"字面量"的术语,字面量(literal)用于表达源代码中一个固定值的表示法(notation)&…

【蓝桥杯每日一题】差分算法

🍎 博客主页:🌙披星戴月的贾维斯 🍎 欢迎关注:👍点赞🍃收藏🔥留言 🍇系列专栏:🌙 蓝桥杯 🌙我与杀戮之中绽放,亦如黎明的花…

因果推断方法(一)合成控制

知道的跳过下面的简单介绍: 就是比如广告主投放了10w元,那么他的收益怎么算?哪些订单就是广告带来的,哪些是不放广告也会购买? 合成控制法是目前我实际应用发现最好用的。置信度高,且容易理解。 简单讲下思…

当我尝试问了chatGPT几个问题之后,我感到了危机......

问题1 : vue3 框架的bug有哪些? 组件内部的状态更新不及时:由于Vue3使用Proxy来实现响应式,在某些情况下,组件内部的状态更新不及时,导致组件的渲染出现问题。 组件内部的数据更新不及时:由于V…

【概念辨析】二维数组传参的集中可能性

一、二维数组传参竟然不是用二级指针进行接收? 今天进行再一次的二级指针学习时,发现了一条以前没怎么注意过的知识点:二维数组进行传参只能用二维数组(不能省略列)进行接收或者是数组指针。 问题复现代码如下&#xf…

MybatisPlus------插件(分页、乐观锁)通用枚举类(九)

MybatisPlus------插件(分页、乐观锁)(九) MybatisPlus自带分页插件,只要简单的配置就可以实现分页功能。 分页插件 创建分页插件拦截器 // 配置类 Configuration // 扫描mapper接口所在的包 MapperScan("com…

北京/东莞/广州/深圳2023年上半年软考(中/高级)报名>>>

软考是全国计算机技术与软件专业技术资格(水平)考试(简称软考)项目,是由国家人力资源和社会保障部、工业和信息化部共同组织的国家级考试,既属于国家职业资格考试,又是职称资格考试。 系统集成…