Android深色模式

參考鏈接:

鏈接1

鏈接2

========================================================

特別注意:經(jīng)過(guò)我們?cè)趯?shí)際開(kāi)發(fā)中的不斷實(shí)驗(yàn)和完善天通,只用鏈接2中的方法就可以完美做到APP整體的深色模式辩越,無(wú)需參考鏈接1的方法漩仙;當(dāng)然如有需要也可以研究一下傀蚌。

========================================================

最近公司想做夜間模式拯钻,于是在網(wǎng)上進(jìn)行了搜索,發(fā)現(xiàn)一些三方庫(kù)已經(jīng)很久不更新了,于是轉(zhuǎn)而參考上面的兩個(gè)鏈接,利用系統(tǒng)特性研究出一套夜間模式的方法市埋,這套方法代碼量比較小,適用性強(qiáng)恕刘,能夠很好的滿足我司當(dāng)前的需求缤谎;

開(kāi)發(fā)思路:我最開(kāi)始看到的是鏈接1,然后根據(jù)鏈接1開(kāi)搞的過(guò)程中發(fā)現(xiàn)褐着,里面的示例代碼不全坷澡,在xml中設(shè)置的字體顏色無(wú)法修改,本人能力有限含蓉,百度之后也無(wú)法解決這個(gè)問(wèn)題洋访,于是轉(zhuǎn)而看網(wǎng)上的其他方法并找到了鏈接2,通過(guò)實(shí)踐發(fā)現(xiàn)鏈接2可以很好的修改xml中設(shè)置的背景色和字體色以及自定義drawable背景中的顏色谴餐,完美彌補(bǔ)了鏈接1的不足,但是鏈接2不能對(duì)代碼中動(dòng)態(tài)設(shè)置的字體顏色和背景色進(jìn)行修改呆抑,而鏈接1又很好的完成了這一點(diǎn)岂嗓;于是二者結(jié)合,成功解決夜間模式問(wèn)題

總結(jié):

鏈接1:負(fù)責(zé)修改代碼中動(dòng)態(tài)設(shè)置的字體顏色和背景色鹊碍;
鏈接2:負(fù)責(zé)修改 xml 和 drawable 中設(shè)置的字體顏色和背景色厌殉;

鏈接1的實(shí)現(xiàn)思路:

1:創(chuàng)建res-night文件夾食绿,注意一定要和 res 文件夾是同級(jí):


image.png

2:在build.gradle中 android{} 下添加以下代碼:

//適配暗黑模式
    sourceSets {
        main {
            java {
                srcDir 'src/main/java'
            }
            res.srcDirs += 'src/main/res'
            res.srcDirs += 'src/main/res-night'
        }
    }

3:在Application類中添加以下代碼:

 private  Resources mSkinResources = null;

 @Override
    public Resources getResources() {
        if (mSkinResources == null) {
            mSkinResources = new SkinResources(this,super.getResources());
        }
        return mSkinResources;
    }

4:SkinResources 類源碼:

class SkinResources(context: Context, res: Resources) : Resources(res.assets, res.displayMetrics, res.configuration) {

    val contextRef: WeakReference<Context> = WeakReference(context)

    override fun getDrawableForDensity(id: Int, density: Int, theme: Theme?): Drawable? {
        return super.getDrawableForDensity(resetResIdIfNeed(contextRef.get(), id), density, theme)
    }

    override fun getColor(id: Int, theme: Theme?): Int {
        return super.getColor(resetResIdIfNeed(contextRef.get(), id), theme)
    }

    override fun getColorStateList(id: Int, theme: Theme?): ColorStateList {
        return super.getColorStateList(resetResIdIfNeed(contextRef.get(), id), theme)
    }

    private fun resetResIdIfNeed(context: Context?, resId: Int): Int {
        // 非暗黑無(wú)需替換資源 ID
        val boolean = SPUtils.getBoolean(context, "mode", false) //默認(rèn)為白天模式

        if (context == null || !boolean)
        {
            return resId
        }
        var newResId = resId
        val res = context.resources
        try {
            val resPkg = res.getResourcePackageName(resId)
            // 非本包資源無(wú)需替換
            if (context.packageName != resPkg) return newResId

            val resName = res.getResourceEntryName(resId)
            val resType = res.getResourceTypeName(resId)
            // 獲取對(duì)應(yīng)暗黑皮膚的資源 id
            val id = res.getIdentifier("${resName}_night", resType, resPkg)

            if (id != 0) newResId = id
        } finally {
            return newResId
        }
    }
}

5:給 res-night 文件夾中的colors文件添加顏色,具體要映射多少顏色公罕,需要根據(jù)項(xiàng)目情況來(lái)定器紧,這里舉例如下:
res 文件夾中colors中的白色:

    <color name="white">#ffffff</color>

在這里應(yīng)該是:

       <color name="white_night">#000000</color>

到此為止鏈接1中需要做的事情已經(jīng)做完了

================================ 分割線 ================================

鏈接2中的步驟:

1:在Application類的onCreate()中添加以下代碼:

      boolean isNight = SPUtils.getBoolean(this, "mode", false); //默認(rèn)為白天模式
      if (isNight)
        {
            //這個(gè)方法一設(shè)置就會(huì)全局生效
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
        }else {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
        }

2:在res文件夾下創(chuàng)建values-night文件夾,如下:


image.png

3:colors文件中顏色對(duì)應(yīng)如下:

    <color name="white">#ffffff</color>

在這里應(yīng)該是:

       <color name="white">#000000</color>

到此為止鏈接2中需要做的事情已經(jīng)做完了楼眷,下面是暗黑模式的開(kāi)關(guān)部分:

val isNight = SPUtils.getBoolean(this, "mode",false)
SPUtils.put(this,"mode",!isNight)
if (!isNight)
   {
          //這個(gè)方法一設(shè)置就會(huì)全局生效
          AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
    }else{
           AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
   }

6:深色模式適配注意點(diǎn):

a:所有用到的色值铲汪,盡量使用colors中定義好的,如果colors中沒(méi)有罐柳,則需要添加到colors中

b:在對(duì)colors中添加色值的時(shí)候掌腰,需要先看一下colors中是否已經(jīng)有這個(gè)色值漓骚,如果有就復(fù)用惧笛,不要再新起一個(gè)名字

c:不要在代碼或者xml中直接使用16進(jìn)制的色值,比如使用:#ffffff 這種的

d:如果設(shè)計(jì)圖中的色值在colors沒(méi)有定義叠纷,但是和colors中的某個(gè)色值很接近肮蛹,比如:設(shè)計(jì)圖中是#f6f6f6勺择,而color中 #f5f5f5 ,這時(shí)要找設(shè)計(jì)確認(rèn)是否改成 #f5f5f5伦忠,這里涉及到一個(gè)風(fēng)格統(tǒng)一的問(wèn)題

e:圖標(biāo)盡量使用iconfont省核,比如返回按鈕,iconfont的色值使用colors中定義好的

f:如果控件的顏色在深色和淺色兩種模式下需要保持一致缓苛,比如Textview的字體顏色芳撒,在深色和淺色下都需要是白色,則使用colors中的white_for_night未桥;如果colors中沒(méi)有這個(gè)色值笔刹,則增加一個(gè): 色值_for_night

g:深色模式對(duì)應(yīng)的色值合集為:values-night/colors 和 res-night/values/colors,在最終上線的時(shí)候冬耿,這兩個(gè)文件里面的色值盡量保持一致

h:頂部侵入式狀態(tài)欄:有的頁(yè)面在設(shè)置深色模式之后舌菜,狀態(tài)欄的背景色和字體顏色會(huì)有問(wèn)題,需要注意一下

i:深色模式的開(kāi)關(guān)在設(shè)置頁(yè)面”文字大小“按鈕的下面亦镶,如果是隱藏狀態(tài)日月,需要改成visibility

j:深色模式做完必須得讓設(shè)計(jì)驗(yàn)收

k:代碼中動(dòng)態(tài)設(shè)置顏色的時(shí)候,必須要傳入當(dāng)前頁(yè)面的上下文缤骨,否則系統(tǒng)設(shè)置了深色模式爱咬,但是APP沒(méi)開(kāi)啟深色模式的情況下,也會(huì)走res中的res-night下的colors绊起,從而導(dǎo)致顯示深色模式的情況精拟,比如:

ContextCompat.getColor(BaseApplication.mTopActivity, color_id);

中,必須傳入?yún)?shù)一的上下文

7:部分機(jī)型跟隨系統(tǒng)的適配問(wèn)題:

a:在實(shí)際開(kāi)發(fā)的時(shí)候,我們?cè)黾恿烁S系統(tǒng)的功能蜂绎,但是在魅族手機(jī)和榮耀手機(jī)上更改系統(tǒng)為深色或者淺色模式的時(shí)候栅表,APP中檢測(cè)不到系統(tǒng)的更改,拿到的始終是淺色模式师枣;為此我們?cè)黾恿艘韵路椒▉?lái)修復(fù)這個(gè)問(wèn)題:
b:在清單文件的application標(biāo)簽下增加:android:configChanges="uiMode"
c:在application的繼承類中增加以下代碼:

 @Override
    public void onConfigurationChanged(@NonNull android.content.res.Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (DarkModeUtil.INSTANCE.isInit() && DarkModeUtil.INSTANCE.isFollowSystem()) {
            int uiMode = newConfig.uiMode & android.content.res.Configuration.UI_MODE_NIGHT_MASK;
 //這里需要先判斷當(dāng)前是否是跟隨系統(tǒng)怪瓶,如果是跟隨系統(tǒng),并且跟系統(tǒng)的樣式不一致践美,再進(jìn)行改變洗贰,并且修改深色模式的SP
//中的布爾值;這里就先省略了拨脉,只保留核心代碼
            switch (uiMode) {
                case android.content.res.Configuration.UI_MODE_NIGHT_YES: // 深色模式
                   if (BaseApplication.mTopActivity != null) {
                            BaseApplication.mTopActivity.recreate();
                        }
                    break;
                case android.content.res.Configuration.UI_MODE_NIGHT_NO: // 淺色模式
                     if (BaseApplication.mTopActivity != null) {
                            BaseApplication.mTopActivity.recreate();
                        }
                    break;
                default: // 未知模式
                    break;
            }
        }
    }

到此為止暗黑模式就基本完成了哆姻,剩下的就是一些效果的優(yōu)化,比如開(kāi)關(guān)暗黑模式時(shí)當(dāng)前頁(yè)面會(huì)閃爍玫膀,這個(gè)在鏈接2中有解決方法矛缨,可以自行參考,如有其他問(wèn)題可以留言帖旨;最后贈(zèng)人玫瑰箕昭,手留余香,參考完記得點(diǎn)贊+關(guān)注

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末解阅,一起剝皮案震驚了整個(gè)濱河市落竹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌货抄,老刑警劉巖述召,帶你破解...
    沈念sama閱讀 222,378評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蟹地,居然都是意外死亡积暖,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)怪与,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)夺刑,“玉大人,你說(shuō)我怎么就攤上這事分别”樵福” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,983評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵耘斩,是天一觀的道長(zhǎng)沼填。 經(jīng)常有香客問(wèn)我,道長(zhǎng)括授,這世上最難降的妖魔是什么倾哺? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,938評(píng)論 1 299
  • 正文 為了忘掉前任轧邪,我火速辦了婚禮,結(jié)果婚禮上羞海,老公的妹妹穿的比我還像新娘。我一直安慰自己曲管,他們只是感情好却邓,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著院水,像睡著了一般腊徙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上檬某,一...
    開(kāi)封第一講書(shū)人閱讀 52,549評(píng)論 1 312
  • 那天撬腾,我揣著相機(jī)與錄音,去河邊找鬼恢恼。 笑死民傻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的场斑。 我是一名探鬼主播漓踢,決...
    沈念sama閱讀 41,063評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼漏隐!你這毒婦竟也來(lái)了喧半?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,991評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤青责,失蹤者是張志新(化名)和其女友劉穎挺据,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體脖隶,經(jīng)...
    沈念sama閱讀 46,522評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扁耐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浩村。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片做葵。...
    茶點(diǎn)故事閱讀 40,742評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖心墅,靈堂內(nèi)的尸體忽然破棺而出酿矢,到底是詐尸還是另有隱情,我是刑警寧澤怎燥,帶...
    沈念sama閱讀 36,413評(píng)論 5 351
  • 正文 年R本政府宣布瘫筐,位于F島的核電站,受9級(jí)特大地震影響铐姚,放射性物質(zhì)發(fā)生泄漏策肝。R本人自食惡果不足惜肛捍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望之众。 院中可真熱鬧拙毫,春花似錦、人聲如沸棺禾。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,572評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)膘婶。三九已至缺前,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間悬襟,已是汗流浹背衅码。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,671評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留脊岳,地道東北人逝段。 一個(gè)月前我還...
    沈念sama閱讀 49,159評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像逸绎,于是被迫代替她去往敵國(guó)和親惹恃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 前言 由于項(xiàng)目需要棺牧,近段時(shí)間開(kāi)發(fā)的夜間模式功能巫糙。主流的方案如下:1、通過(guò)切換theme實(shí)現(xiàn)2颊乘、通過(guò)resource...
    三十二蟬閱讀 14,193評(píng)論 8 87
  • 夜幕降臨参淹,他走在馬路上,回想著今天發(fā)生的一切乏悄,他不敢相信事情就這樣發(fā)生了浙值。他最終還是決定撥打那個(gè)電話,掏出手機(jī)檩小,解...
    章魚(yú)老王閱讀 9,849評(píng)論 9 49
  • 一开呐、android 平臺(tái)常見(jiàn)的換膚方案. Android 平臺(tái)常見(jiàn)的額換膚方式總結(jié)起來(lái)有如下三種: 1.設(shè)置set...
    大鵬的鵬閱讀 4,313評(píng)論 0 4
  • 從API23后,Android就有自帶的api能夠?qū)崿F(xiàn)夜間模式與白天模式的切換规求,用到的就是AppCompatDel...
    灰丨色閱讀 17,919評(píng)論 1 21
  • 最近項(xiàng)目中做一款閱讀器筐付,其中包含夜間模式和白天模式切換功能,最開(kāi)始的想法是當(dāng)點(diǎn)擊了夜晚模式阻肿,手動(dòng)更新背景顏色瓦戚、文字...
    史蒂芬諾夫斯基閱讀 4,325評(píng)論 3 16