Zhujiang |作者
承香墨影 |校對
https://juejin.im/post/5e95633951882573c2192501 |原文
一、前言
第一次聽到暗黑模式的時候,感覺好酷啊,聽着就好看(也不知道我怎麼聽出來的)。
蘋果在前幾年就有暗黑模式的風聲,好像是在 iOS11、iOS12 的時候就說要推出了,結果愣生生等到了 iOS13 暗黑模式才推出。
iOS13 推出到現在已經大半年了,系統應用沒得說,完美適配,三方應用也都陸續支持了暗黑模式,就連微信在前段時間的更新中也實現了暗黑模式,先來欣賞下微信的暗黑模式吧!
二、正文
既然蘋果實現了暗黑模式,那麼安卓肯定不能落下啊,所以在 Android-10(Q-API Level 29)中支持了暗黑模式,不過官方的叫法爲 Dark theme,怎麼翻譯都行,先來看一下官方對暗黑模式的定義吧:
這裏就不逐字翻譯了,主要來說一下暗黑模式的好處吧:
手機的屏幕目前大部分都已經升級成了 OLED 屏幕(當然還有一部分手機還是 LCD 屏幕),OLED 屏幕顯示黑色的時候不會發光,可以大大減小功耗。
提高了弱視用戶和對強光敏感的用戶的可見性。
使任何人在昏暗的環境中都更容易使用設備。
怎樣開啓暗黑模式就不多說了,手機廠商不同,開啓方式不同,各大手機廠商魔改的系統,有時候真的找不到在哪設置,自行百度一下吧。
設置暗黑主題
爲了支持 Dark 主題,必須將應用的主題設置爲,繼承自 DayNight 主題(res/values/styles.xml):
<style name="AppTheme"
parent="Theme.AppCompat.DayNight">
還可以使用 MaterialComponents 的深色主題:
https://material.io/develop/android/theming/dark
<style name="AppTheme"
parent="Theme.MaterialComponents.DayNight">
這會將應用程序的主主題與系統控制的夜間模式標誌相關聯,併爲應用程序提供默認的深色主題(啓用時)。當系統的主題切換時,應用也會隨之切換主題。
“這就完了?”
“對啊,主題就設置完了。”
“那我如果想要自定義主題呢?”
大家日常開發中肯定會有這種需求,官方定義的主題不完全能滿足我們的需求,這時候就需要來自定義主題了,谷歌也爲我們想到了這一點。
普通模式下咱們不需要動,該怎麼寫怎麼寫,然後在 res
下再新建一個 values-night
的文件夾,然後把你自定義的放進去,name 名爲 styles.xml
中對應的主題名稱就可以了。
來看一下吧:
這樣設置完就 OK 了。
“不對啊,這只是主題變了,那我的 Activity 的背景、字體的顏色、圖片等等該怎麼辦呢?”
“彆着急,下面就要說了。”
這裏一定要注意,主題和樣式應避免在淺色主題下使用硬編碼的顏色或圖標,應該使用主題屬性(首選)或夜間限定的資源。來了解下兩個最重要的主題屬性吧:
?android:attr/textColorPrimary:這是一種通用的文本顏色。淺色主題爲近黑色,深色主題爲近白。它包含禁用狀態。
?attr/colorControlNormal:通用圖標顏色。它包含禁用狀態。
當然肯定不是必須要使用上面官方提供的兩個主題屬性,想自定義就自定義啊!眼睛尖的可能已經看見了,上面的圖片中的 values-night
中除了放有 style.xml
外還有 colors.xml
,對,沒錯,咱們只要把顏色信息放入到 colors.xml
中然後根據需求寫上兩個顏色就好了。
但還是建議使用 Material Design Components,因爲它的顏色主題系統 (例如主題屬性 ?attr/colorSurface 和 ?attr/colorOnSurface)可以輕鬆訪問合適的顏色。
https://material.io/develop/android/
https://material.io/develop/android/theming/color/
“大哥,背景顏色和字體顏色我知道怎麼改了,圖片呢?圖片咋辦啊!”
“來了來了,猴急猴急的!”
圖片設置其實和顏色差不多,也是兩套資源,比如你的 drawable
文件夾下有一張 aaa.jpg
的圖片,你想在暗黑模式下換成另外一張圖片,那麼你就可以新建一個 drawable-night
的文件夾,在裏面放上你的另外一張圖片就行了,注意, 圖片名稱一定要和 drawable
中的對應。
同理,drawable-xhdpi
、drawable-xxhdpi
就是再建兩個文件夾:drawable-night-xhdpi
、drawable-night-xxhdpi
,然後放入對應圖片就行了。
“什麼?你想看一下效果?那好吧,如你所願,這真的是你,要是別人我都不讓他看。。。。”
怎麼樣,效果還可以吧?
四、應用內修改主題
“我還想自己主動切換,不想隨着系統換才換”
“來,你過來,你還想幹啥,說,來來來,說吧”
“我就想自己主動設置是否跟隨系統切換主題。。。我看好多應用都有這個功能”
哎,既然你發自內心的問了,那我就大發慈悲的告訴你:當然可以喲!
一般來說應用都會有幾個選項供你選擇,分別是:普通模式、暗黑模式、跟隨系統,對吧?
谷歌也給了我們這幾個選項,可以直接進行設置:
Light - MODE_NIGHT_NO:https://developer.android.google.cn/reference/androidx/appcompat/app/AppCompatDelegate.html#MODE_NIGHT_NO
黑暗 - MODE_NIGHT_YES:https://developer.android.google.cn/reference/androidx/appcompat/app/AppCompatDelegate.html#MODE_NIGHT_YES
由省電模式設定 - MODE_NIGHT_AUTO_BATTERY:https://developer.android.google.cn/reference/androidx/appcompat/app/AppCompatDelegate.html#MODE_NIGHT_AUTO_BATTERY
系統預設 - MODE_NIGHT_FOLLOW_SYSTEM:https://developer.android.google.cn/reference/androidx/appcompat/app/AppCompatDelegate.html#MODE_NIGHT_FOLLOW_SYSTEM
咱們剛纔所說的就是 Light、黑暗和系統預設,省電模式這裏就不寫, 如果有需求可以進行實驗。
切換主題的方法也很簡單,直接調用下面方法就行:
AppCompatDelegate.setDefaultNightMode()
就一行代碼就行了,參數需要傳入上面的四種模式之一。
來吧,那就寫一下代碼吧,按照上面的要求寫三個按鈕,分別來實現普通模式、暗黑模式和系統模式吧:
override fun onClick(v: View) {
when(v.id){
R.id.btnLight ->{
setDefaultNightMode(MODE_NIGHT_NO)
}
R.id.btnDark ->{
setDefaultNightMode(MODE_NIGHT_YES)
}
R.id.btnDefault ->{
setDefaultNightMode(MODE_NIGHT_FOLLOW_SYSTEM)
}
}
}
這個代碼應該不需要解釋了,上面解釋的已經夠多了。來看一下實現效果吧:
五、配置變更
“大哥,我又想了下,如果有的頁面正在播放視頻,我想要延遲配置更改該怎麼辦啊?”
“來,你過來小兄弟,逗着大哥玩呢?這一天天的!”
來吧,有需求就得有實現,谷歌大大已經爲我們都想好了,應用可以通過聲明每個 Activity 可以處理 uiMode 配置更改來處理 Dark 主題本身的實現:https://developer.android.google.cn/reference/android/content/res/Configuration#uiMode
<activity
android:name=".MyActivity"
android:configChanges="uiMode" />
當 Activity 聲明它處理配置更改時,onConfigurationChanged()
將在主題更改時調用其方法。要檢查當前主題是什麼,應用可以運行如下代碼:Activity#onConfigurationChanged(Configuration)
val currentNightMode = configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
when (currentNightMode) {
Configuration.UI_MODE_NIGHT_NO -> {} // 夜間模式未啓用,我們正在使用淺色主題
Configuration.UI_MODE_NIGHT_YES -> {} // 夜間模式啓用,我們使用的是深色主題
}
六、總結
文章到這裏基本結束了,谷歌用行動告訴我們儘量不要硬編碼,出來混都是要還的,硬編碼一時爽,一直硬編碼一直爽,哈哈哈。
文中源碼已上傳 Github:https://github.com/zhujiang521/Skin
推薦閱讀:
本文對你有幫助嗎?留言、轉發、點好看是最大的支持,謝謝!
公衆號後臺回覆成長『成長』,將會得到我準備的學習資料。