电子书阅读器上的浏览器 [Day18] 支援夜间模式

夜间模式在电子书阅读器上通常效果不会很好,黑色的底色会造成很多残影。不过,因为我也会在一般手机上使用这个 browser ,所以能够支援夜间模式的话,也可以让一般手机的使用者享受到许多 这个 browser 独有的功能。这功能算是偷渡进来的吧,但毕竟开发了,还是稍微讲解一下是怎麽支援的。

颜色设定调整

在这系列的一开头有提到,为了要提高图案的对比度,当时我很偷懒的直接把黑色套到了所有需要显示为深色的地方,包含 Layout 背景或是图案的轮廓。但为了要让 browser 支援夜间模式,我必须把这些地方再改成会随着系统显示模式设定而读取不同颜色值才行。

这是一项苦差事,不过 Android Studio 的 Find & Replace All… 拯救了我大部分的时间,我总共修改了 72 张的图案。没想到这麽一个小小的 App,竟然包含了这麽多图案。

情况 范例
style https://ithelp.ithome.com.tw/upload/images/20210917/20140260GTrgOjLEpv.png
图案 https://ithelp.ithome.com.tw/upload/images/20210917/20140260gLRwANQZ3f.png
layout https://ithelp.ithome.com.tw/upload/images/20210917/20140260iAs7KanzoA.png

Github 上可以看到相关的修改 commit 内容:

再来是我们需要另外建一份 style.xml,把它放在 app/src/main/res/values-night/style.xml 。这样子当系统设定改变时,系统才会自动来读取这份我们设定好在夜间模式时要使用的 style。

下面是 values-night/style.xml 内容的片段:

https://ithelp.ithome.com.tw/upload/images/20210917/20140260779dVlpAJK.png

夜间模式设定

将图案的颜色改为 ?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()
             }
         }
     }

WebView 的夜间模式支援

对於 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。这个坑有点大,所以先还是采取比较容易实作的方式来完成这功能。

参考原始码版本

下一篇开始,会有好几天的内容会是围绕着翻译的功能打转。这是一个对我自己来说很常用的功能,所以对於这功能的打磨和开发,也是花了最多心思和时间。敬请期待。


<<:  DAY3-EXCEL统计分析:认识离散型机率

>>:  [Day-03] - Spring Framework Introduction

Day17 Let's ODOO: Data Files

通常我们在写module的时候,会需要一些初始资料或是固定需要的资料,我们可以定义资料在创立Mode...

Day06 建构Project(2)

我们昨天建立完Project後,我们再仔细深入研究的话,会发现第二层的Test里面还有其他额外的四个...

[Day - 21] - 规律的一天从Spring Scheduled 开始

Abstract 大家每天都是新的开始,都有24H小时给你规划,系统跟人类一样都是有自己的周期性计画...

JavaScript入门 Day18_function介绍

今天要讲的是function,那他是什麽呢 他就像是一段已经写好的code,然後当我们需要他的时候 ...

Promise

前言 不知道大家学习英语的时候有没有过明明语法规则都记清楚了,却还是不清楚实际如何运用的经验,或是只...