夜間模式在電子書閱讀器上通常效果不會很好,黑色的底色會造成很多殘影。不過,因為我也會在一般手機上使用這個 browser ,所以能夠支援夜間模式的話,也可以讓一般手機的使用者享受到許多 這個 browser 獨有的功能。這功能算是偷渡進來的吧,但畢竟開發了,還是稍微講解一下是怎麼支援的。
在這系列的一開頭有提到,為了要提高圖案的對比度,當時我很偷懶的直接把黑色套到了所有需要顯示為深色的地方,包含 Layout 背景或是圖案的輪廓。但為了要讓 browser 支援夜間模式,我必須把這些地方再改成會隨著系統顯示模式設定而讀取不同顏色值才行。
這是一項苦差事,不過 Android Studio 的 Find & Replace All… 拯救了我大部分的時間,我總共修改了 72 張的圖案。沒想到這麼一個小小的 App,竟然包含了這麼多圖案。
情況 | 範例 |
---|---|
style | |
圖案 | |
layout |
Github 上可以看到相關的修改 commit 內容:
再來是我們需要另外建一份 style.xml,把它放在 app/src/main/res/values-night/style.xml
。這樣子當系統設定改變時,系統才會自動來讀取這份我們設定好在夜間模式時要使用的 style。
下面是 values-night/style.xml 內容的片段:
將圖案的顏色改為 ?attr/
開頭的顏色後,再來就是要處理系統切換夜間模式的邏輯。首先要建立新的 Application class,設定夜間模式的預設設定。
class EinkBroApplication : Application() {
override fun onCreate() {
super.onCreate()
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
}
這邊的 AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM 表示要遵從目前系統的設定。
再來是當系統 configuration 改變時,Activity 必須要判斷是不是要重啟,並套用新的顏色。
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val nightModeFlags = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
if (nightModeFlags != uiMode) {
restartApp()
}
}
}
對於 browser 來說,其實主要的 UI 只有下方的工具列,大部分的內容還是來自於網頁。所以除了把原生的 UI 介面改成夜間模式外,如果網頁內容也可以隨著系統設定而調整成夜間模式的話,會讓眼睛更加舒適。為了達到這功能,在 WebView 初始化時,可以做以下設定:
private fun initWebView() {
...
if(WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) {
WebSettingsCompat.setForceDarkStrategy(settings, WebSettingsCompat.DARK_STRATEGY_WEB_THEME_DARKENING_ONLY)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val nightModeFlags = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
if (nightModeFlags == Configuration.UI_MODE_NIGHT_YES) {
settings.forceDark = WebSettings.FORCE_DARK_ON
}
}
}
要加入上述的設定,必須額外在 build.gradle 中加入下面的 library 才行
implementation 'androidx.webkit:webkit:1.4.0'
完成上述步驟後,就大功告成啦!目前的作法是當系統設定改變時,會整個重啟目前的 Activity。這種方式有時會失去目前的一些瀏覽狀態。但如果想要在不重啟 Activity 的情況下,達到 UI 都套用成夜間顏色的話,就得要針對畫面上的每個 UI 元件去更新它們的 theme color。這個坑有點大,所以先還是採取比較容易實作的方式來完成這功能。
下一篇開始,會有好幾天的內容會是圍繞著翻譯的功能打轉。這是一個對我自己來說很常用的功能,所以對於這功能的打磨和開發,也是花了最多心思和時間。敬請期待。