暗色模式已经不是什么新鲜玩意了,大家最近看到关于暗色模式最多的内容可能就是iOS版本微信未适配暗色模式面临被AppStore下架的风险。然后今天早上一醒来,发现Android的微信也黑了(因为我手机一直用的暗色模式),然后最近也遇到了一个暗色模式适配的一个坑,就拿出来讲一讲。

适配暗色模式

在开始之前还是提一下,暗色模式的一个适配方式。这个谷歌官方讲的很清楚,方式有两种:

  • 定义两套主题(正常模式和黑暗模式)

这种方式较为复杂,需要在style下定义正常模式和暗色模式两套app_theme,且必须继承自Theme.AppCompat.DayNight.DarkActionBar,然后提取出需要适配暗色模式的属性,最后在BaseActivity的onCreate方法中,根据当前模式设置不同的主题即可。判断系统当前是否暗色模式:

public boolean isDarkMode() {int mode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;return mode == Configuration.UI_MODE_NIGHT_YES;
}
  • 设置forceDarkAllowed属性

这种方式简单粗暴,只需要app_theme中声明

<item name="android:forceDarkAllowed">true</item>

应用会在系统切换暗色时,自动适配,这个前提就是不要使用硬编码颜色值。同样需要准备两套资源,暗色模式需要的资源文件,放在以values-night命名的资源目录下,在不同模式下,会自动读取对应目录下的资源。

forceDrakAllowed不仅可以用在App主题级别,也可以直接使用在View上。如果仅需某个View适配暗色模式,直接在view属性声明即可。同理,如果某个View在暗色模式下,不需要适配,通过设置forceDrakAllowed为false即可,或者通过view.setForceDarkAllowed(false)。

遇到的bug

暗色模式下,状态栏没有反色,导致看不清。

这个很好定位,肯定是StatusBar状态写死了,去代码里面看看

private void setStatusBarColor() {Window window = getWindow();window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);window.setStatusBarColor(Color.TRANSPARENT);window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}

可以看到,之前应该是因为某种业务需要,所以将状态栏设置了LIGHT_STATUS_BAR这个flag。

方案一:

我们知道,如果不认为去设置SystemUI的Visibility,系统会自动根据当前主题颜色来适配状态栏是否进行反色,那么我们如果去掉这个这个人为设置的flag, 是否就可以解决这个问题。

private void setStatusBarColor() {Window window = getWindow();window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);window.setStatusBarColor(Color.TRANSPARENT);//去掉LIGHT_STATUS_BAR这个flag//window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}

结果如下:

暗色模式虽然状态栏反色了,但是正常模式下,又看不到了。也就是说,暗色模式下的状态栏,需要自己适配。并且,Activity的内容与状态栏出现了重叠。

方案二:

既然无法自动反色,那就适配咯,原本逻辑咱们不改动,加个判断在暗色模式时,咱们设置一个DRAK_STATUS_BAR属性是不是就可以了。开玩笑哈,View属性里面并没有这个flag,需要通过位运算来处理

private void setStatusBarColor() {Window window = getWindow();window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);window.setStatusBarColor(Color.TRANSPARENT);if (isDarkMode()) {int uiOption = window.getDecorView().getSystemUiVisibility();//没有DARK_STATUS_BAR属性,通过位运算将LIGHT_STATUS_BAR属性去除window.getDecorView().setSystemUiVisibility(uiOption & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);} else {window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);}
}

结果如下:

正常模式和暗色模式,状态栏都已经正常反色,但是暗色模式下,Activity内容依然与状态栏重叠。

方案三:

通过对比不难发现,只有暗色模式重叠,无非就是因为我们保留了之前所设置的FLAG,这里要注意,这里的FLAG是通过set方法来设置的,也就是说,后面的只会覆盖前面的,而不像我们平时所使用的addFlags,这个是叠加的。

再来回顾一下,没有修改前的代码:

private void setStatusBarColor() {Window window = getWindow();window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);//第一次set了两个属性window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);window.setStatusBarColor(Color.TRANSPARENT);//这里又一次set,也就是前面的e两个属性根本没有使用window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}

而我们出现重叠的原因,就是因为保留了之前的属性,其中SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN就是导致重叠的真凶,作用是在不隐藏StatusBar的情况下,将view所在window的显示范围扩展到StatusBar下面。之所以正常模式下,不会出现重叠,是因为二次设置LIGHT_STATUS_BAR会覆盖前面的属性。

很明显,我们的内容并不需要延伸至状态栏下,所以前面的代码就是无用的,删除即可。

private void setStatusBarColor() {Window window = getWindow();window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);//window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE//  | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);window.setStatusBarColor(Color.TRANSPARENT);int uiOption = window.getDecorView().getSystemUiVisibility();if (isDarkMode()) {//没有DARK_STATUS_BAR属性,通过位运算将LIGHT_STATUS_BAR属性去除window.getDecorView().setSystemUiVisibility(uiOption & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);} else {//这里是要注意的地方,如果需要补充新的FLAG,记得要带上之前的然后进行或运算window.getDecorView().setSystemUiVisibility(uiOption | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);}
}

最后的真凶,并不是暗色模式导致了重叠,而是原代码作者留下的坑。主要还是对于SystemUI Flag的一些属性不熟导致。OK,修改完效果​如下。

对于SystemUI的一些FLAG作用不清楚的同学,​可以参考下面这个文章:

https://www.jianshu.com/p/e6656707f56c​


更多完整面试专题和进阶知识分享,尽在“Android扫地僧”

Android Q暗色模式适配踩坑—状态栏相关推荐

  1. Android 10深色主题适配踩坑记录

    1. 问题简述 Android 10 推出了深色主题,便于用户根据白天和夜晚自由切换合适的主题.在适配的过程中,要特别注意,切换主题会导致当前activity被重建,也就是会重新走一遍Activity ...

  2. 转:android.support升级到androidx踩坑记录

    原文链接:android.support升级到androidx踩坑记录 - 简书 年前想着Google老大之前提醒过将项目升级到androidx,所以年前一通操作猛如虎把Android Studio唰 ...

  3. android gradle权威指南pdf_干货 | 携程 Android 10适配踩坑指南

    作者简介 曙光,携程资深软件工程师,负责市场营销相关研发及管理工作.2019 年 9 月 3 日,Google 发布了 Android 10 正式版.Android 10 聚焦移动创新.安全隐私和数字 ...

  4. React-Native android在windows下的踩坑记

    坑很多,跳之前做好准备.没有VPN的同学请浏览完本文后慎行. 你需要先安装最新版本的node.js(我最后使用的是v4.1.2),前往官网下载>> 注:我win7已经安装过Visual S ...

  5. Android Studio打包~安卓打包踩坑及总结

    一..Android Studio,打开自己的项目中的android,点击确定 二.点击OK后自动执行右上角大象标志.同步项目与Gradle文件. 三.点击最下面一排的build,可以实时看到进度和报 ...

  6. Android SDK 开发——发布使用踩坑之路

    前言 在 Android 开发过程中,有些功能是通用的,或者是多个业务方都需要使用的. 为了统一功能逻辑及避免重复开发,因此将该功能开发成一个 SDK 是相当有必要的. 背景 刚好最近自己遇到了类似需 ...

  7. STM32L051 低功耗模式和踩坑随笔(自用)

    这几天用到了STM32L051的低功耗.之前也接触过低功耗,各种模式有些迷糊,正好整理一下. 手册上说有5个模式,功耗依次递减. 低功耗运行模式:调压器处于低功耗模式,时钟频率受限. 进入方式: 配置 ...

  8. android q 桌面模式,Android Q带来全新桌面模式

    IT之家3月14日消息 谷歌在美国当地时间3月13日(北京时间14日凌晨)正式推送了Android Q的首个Beta版本,"亲儿子"Pixel系列全系手机可以尝鲜体验这最新的系统. ...

  9. Android Q之提前适配攻略(一)(图标适配)

    转自:https://blog.csdn.net/qq_37199105/article/details/89632104 前言: Android Q在2019年的3月份发布了beta1版本,这算是近 ...

最新文章

  1. linux——管理系统设备之磁盘的加密、加密磁盘的挂载及磁盘阵列、配额
  2. Unity3D基础28:Invoke计时函数与碰撞销毁
  3. Bootstrap 使用教程 与jQuery的Ajax方法
  4. Windows10下编译Nginx源码
  5. app测试和web测试的区别
  6. python和c语言的哪个难,r语言和c语言哪个难 r语言和python的区别-与非网
  7. PDF旋转保存居然还能如此高效的办法
  8. 中国标准走进国际视野,首个零信任国际标准的诞生往事
  9. SpringCloudAlibaba——Nacos实现原理详解
  10. 我的挣扎 与 TBtools 的开发
  11. 解决使用ssh工具远程连接到服务器上因为网络波动而需要重连的问题
  12. 简单的RTSP播放器
  13. 克隆虚拟机 - hyperv
  14. 武汉新时标文化传媒有限公司新型网红经济爆发式增长
  15. 【Unity3D】相机
  16. 安居客上市,难挑58大梁?
  17. JAVA设计模式什么鬼(观察者)——作者:凸凹里歐
  18. PostgreSQL 锁等待诊断详解
  19. ldd3学习之七:中断处理
  20. 如何评价OA系统的易用性

热门文章

  1. minui点击分页控件后滚动条置顶
  2. kasp技术原理_SNP检测Massarray法怎么样?中高通量大样本适用吗?
  3. Hadoop Java对应版本号
  4. Android 自定义相机黑屏
  5. 柏西机器人_《勿忘我》孔木猴 ^第15章^ 最新更新:2020-08-03 17:37:51 晋江文学城_手机版...
  6. 在EntityFramework中使用 nock的方法。
  7. 友盟统计使用及添加测试设备(设备ID及Mac地址识别)
  8. cobble批量装机原理与部署
  9. Android实现仿QQ登录可编辑下拉菜单
  10. Cannot create symlink/symbolic to `xxx': Operation not supported