Android Q暗色模式适配踩坑—状态栏
暗色模式已經(jīng)不是什么新鮮玩意了,大家最近看到關(guān)于暗色模式最多的內(nèi)容可能就是iOS版本微信未適配暗色模式面臨被AppStore下架的風(fēng)險(xiǎn)。然后今天早上一醒來(lái),發(fā)現(xiàn)Android的微信也黑了(因?yàn)槲沂謾C(jī)一直用的暗色模式),然后最近也遇到了一個(gè)暗色模式適配的一個(gè)坑,就拿出來(lái)講一講。
適配暗色模式
在開(kāi)始之前還是提一下,暗色模式的一個(gè)適配方式。這個(gè)谷歌官方講的很清楚,方式有兩種:
- 定義兩套主題(正常模式和黑暗模式)
這種方式較為復(fù)雜,需要在style下定義正常模式和暗色模式兩套app_theme,且必須繼承自Theme.AppCompat.DayNight.DarkActionBar,然后提取出需要適配暗色模式的屬性,最后在BaseActivity的onCreate方法中,根據(jù)當(dāng)前模式設(shè)置不同的主題即可。判斷系統(tǒng)當(dāng)前是否暗色模式:
public boolean isDarkMode() {int mode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;return mode == Configuration.UI_MODE_NIGHT_YES; }- 設(shè)置forceDarkAllowed屬性
這種方式簡(jiǎn)單粗暴,只需要app_theme中聲明
<item name="android:forceDarkAllowed">true</item>應(yīng)用會(huì)在系統(tǒng)切換暗色時(shí),自動(dòng)適配,這個(gè)前提就是不要使用硬編碼顏色值。同樣需要準(zhǔn)備兩套資源,暗色模式需要的資源文件,放在以values-night命名的資源目錄下,在不同模式下,會(huì)自動(dòng)讀取對(duì)應(yīng)目錄下的資源。
forceDrakAllowed不僅可以用在App主題級(jí)別,也可以直接使用在View上。如果僅需某個(gè)View適配暗色模式,直接在view屬性聲明即可。同理,如果某個(gè)View在暗色模式下,不需要適配,通過(guò)設(shè)置forceDrakAllowed為false即可,或者通過(guò)view.setForceDarkAllowed(false)。
遇到的bug
暗色模式下,狀態(tài)欄沒(méi)有反色,導(dǎo)致看不清。
這個(gè)很好定位,肯定是StatusBar狀態(tài)寫(xiě)死了,去代碼里面看看
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); }可以看到,之前應(yīng)該是因?yàn)槟撤N業(yè)務(wù)需要,所以將狀態(tài)欄設(shè)置了LIGHT_STATUS_BAR這個(gè)flag。
方案一:
我們知道,如果不認(rèn)為去設(shè)置SystemUI的Visibility,系統(tǒng)會(huì)自動(dòng)根據(jù)當(dāng)前主題顏色來(lái)適配狀態(tài)欄是否進(jìn)行反色,那么我們?nèi)绻サ暨@個(gè)這個(gè)人為設(shè)置的flag, 是否就可以解決這個(gè)問(wèn)題。
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這個(gè)flag//window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); }結(jié)果如下:
暗色模式雖然狀態(tài)欄反色了,但是正常模式下,又看不到了。也就是說(shuō),暗色模式下的狀態(tài)欄,需要自己適配。并且,Activity的內(nèi)容與狀態(tài)欄出現(xiàn)了重疊。
方案二:
既然無(wú)法自動(dòng)反色,那就適配咯,原本邏輯咱們不改動(dòng),加個(gè)判斷在暗色模式時(shí),咱們?cè)O(shè)置一個(gè)DRAK_STATUS_BAR屬性是不是就可以了。開(kāi)玩笑哈,View屬性里面并沒(méi)有這個(gè)flag,需要通過(guò)位運(yùn)算來(lái)處理
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();//沒(méi)有DARK_STATUS_BAR屬性,通過(guò)位運(yùn)算將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);} }結(jié)果如下:
正常模式和暗色模式,狀態(tài)欄都已經(jīng)正常反色,但是暗色模式下,Activity內(nèi)容依然與狀態(tài)欄重疊。
方案三:
通過(guò)對(duì)比不難發(fā)現(xiàn),只有暗色模式重疊,無(wú)非就是因?yàn)槲覀儽A袅酥八O(shè)置的FLAG,這里要注意,這里的FLAG是通過(guò)set方法來(lái)設(shè)置的,也就是說(shuō),后面的只會(huì)覆蓋前面的,而不像我們平時(shí)所使用的addFlags,這個(gè)是疊加的。
再來(lái)回顧一下,沒(méi)有修改前的代碼:
private void setStatusBarColor() {Window window = getWindow();window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);//第一次set了兩個(gè)屬性window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);window.setStatusBarColor(Color.TRANSPARENT);//這里又一次set,也就是前面的e兩個(gè)屬性根本沒(méi)有使用window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); }而我們出現(xiàn)重疊的原因,就是因?yàn)楸A袅酥暗膶傩?#xff0c;其中SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN就是導(dǎo)致重疊的真兇,作用是在不隱藏StatusBar的情況下,將view所在window的顯示范圍擴(kuò)展到StatusBar下面。之所以正常模式下,不會(huì)出現(xiàn)重疊,是因?yàn)槎卧O(shè)置LIGHT_STATUS_BAR會(huì)覆蓋前面的屬性。
很明顯,我們的內(nèi)容并不需要延伸至狀態(tài)欄下,所以前面的代碼就是無(wú)用的,刪除即可。
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()) {//沒(méi)有DARK_STATUS_BAR屬性,通過(guò)位運(yùn)算將LIGHT_STATUS_BAR屬性去除window.getDecorView().setSystemUiVisibility(uiOption & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);} else {//這里是要注意的地方,如果需要補(bǔ)充新的FLAG,記得要帶上之前的然后進(jìn)行或運(yùn)算window.getDecorView().setSystemUiVisibility(uiOption | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);} }最后的真兇,并不是暗色模式導(dǎo)致了重疊,而是原代碼作者留下的坑。主要還是對(duì)于SystemUI Flag的一些屬性不熟導(dǎo)致。OK,修改完效果?如下。
對(duì)于SystemUI的一些FLAG作用不清楚的同學(xué),?可以參考下面這個(gè)文章:
https://www.jianshu.com/p/e6656707f56c?
更多完整面試專(zhuān)題和進(jìn)階知識(shí)分享,盡在“Android掃地僧”
總結(jié)
以上是生活随笔為你收集整理的Android Q暗色模式适配踩坑—状态栏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 加油站问题
- 下一篇: J语言初步,绝妙的符号系统,神的计算器