Android Q暗色模式适配踩坑—状态栏
暗色模式已經不是什么新鮮玩意了,大家最近看到關于暗色模式最多的內容可能就是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暗色模式适配踩坑—状态栏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 加油站问题
- 下一篇: J语言初步,绝妙的符号系统,神的计算器