文章目录

  • 暗黑模式
    • 为什么我们需要暗黑模式
    • 如何适配暗黑模式
      • Force Dark自动适配
      • 自定义适配
    • 手动切换暗黑模式

暗黑模式

在 2019 年的 Google I/O上,谷歌新发布的android 10终于从系统层级支持暗黑模式,那么为什么我们需要暗黑模式?Android开发者应该如何让自己的app适配暗黑模式?接下来的文章将一一为你解答。

为什么我们需要暗黑模式

在Android 官方文档中,列举了暗黑模式的三个好处:

  1. 可以大大降低功耗(取决于设备的屏幕技术)。
  2. 提高了弱视用户和对强光敏感的用户的可见性。
  3. 使任何人在昏暗的环境中都更容易使用设备。

在OLED显示屏上,当一个像素是纯黑色(十六进制为#000000)的时候,该像素将会被关闭并且不消耗能量,这时如果显示屏显示的是大面积的黑色像素,将会大大降低显示屏消耗的电量。

如何适配暗黑模式

Force Dark自动适配

Android 10 提供 Force Dark 功能。此功能可让开发者快速实现深色主题背景,只需要在 style.xml 中的应用主题中添加这一行代码android:forceDarkAllowed=“true” ,就可以完成自动适配。

<resources>    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">        <item name="colorPrimary">@color/colorPrimary</item>        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>        <item name="colorAccent">@color/colorAccent</item>        <item name="android:forceDarkAllowed">true</item>    </style></resources>

效果对比如下图所示。从结果来看,整体的界面风格好像确实变成了暗黑模式,但是菜单栏并未适配,所以这里我并不推荐你使用这种自动化的方式来实现深色主题,而是应该使用更加复杂一点的实现方式——自定义适配。

图1 正常情况
图2 Force Dark适配

自定义适配

  1. 将App 使用的主题从之前默认的 Light 主题修改为 DayNight
<resources>    <!-- Base application theme. -->    <style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">        <!-- Customize your theme here. -->        <item name="colorPrimary">@color/colorPrimary</item>        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>        <item name="colorAccent">@color/colorAccent</item>    </style>    </resources>
  1. 右击res目录 -> New -> Directory,创建一个values-night目录,然后右击values-night目录 -> New -> Values resource file,创建一个colors-night.xml文件。接着在这个文件中指定深色主题下的颜色值,颜色的命名要与colors.xml相同。
--colors.xml<resources>    <color name="colorPrimary">#008577</color>    <color name="colorPrimaryDark">#00574B</color>    <color name="colorAccent">#D81B60</color>    <color name="colorTextView">#000</color></resources>--colors-night.xml<resources>    <color name="colorPrimary">#303030</color>    <color name="colorPrimaryDark">#232323</color>    <color name="colorAccent">#008577</color>    <color name="colorTextView">#FFFFFF</color></resources>
  1. 为那些在切换为暗黑模式时,需要改变颜色的控件适配,这里我们以TextView为例。
   <TextView       android:id="@+id/name"       android:layout_width="wrap_content"       android:layout_height="wrap_content"       android:textColor="@color/colorTextView"       android:padding="10dp"       android:textSize="20sp"       app:layout_constraintLeft_toLeftOf="parent"       app:layout_constraintTop_toTopOf="parent" />

效果对比如下图。效果明显比自动适配好上不少,算是初步实现了对暗黑模式的适配。

手动切换暗黑模式

目前为止我们已经知道了如何适配暗黑模式,在完成适配之后,我们还需要为用户提供在运行时,切换主题的选项,切换的代码也很简单,在菜单监听中通过getDelegate().setLocalNightMode()来设置当前的模式。

    @Override    public  boolean onOptionsItemSelected(MenuItem mi){        if(mi.isCheckable()){            mi.setChecked(true);        }        switch (mi.getItemId()){            case R.id.mode_light:                getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_NO);                break;            case R.id.mode_dark:                getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);                break;            case R.id.mode_system:                getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);                break;        }        return true;    }

setLocalNightMode()方法接收一个mode参数,用于控制当前应用程序的夜间模式。mode参数主要有以下值可供选择:

  1. MODE_NIGHT_FOLLOW_SYSTEM:默认模式,表示让当前应用程序跟随系统设置来决定使用浅色主题还是深色主题。
  2. MODE_NIGHT_YES:脱离系统设置,强制让当前应用程序使用深色主题。
  3. MODE_NIGHT_NO:脱离系统设置,强制让当前应用程序使用浅色主题
  4. MODE_NIGHT_AUTO_BATTERY:根据手机的电池状态来决定使用浅色主题还是深色主题,如果开启了节点模式,则使用深色主题。

需要注意的是,当调用setLocalNightMode()方法并成功切换主题时,应用程序中所有处于started状态的Activity都会被重新创建,那如果不想Activity重新创建Activity怎么切换主题呢?
这时候我们可以在AndroidManifest中将configChanges设置为uiMode,使当前的Activity避免被重新创建。

<application        android:allowBackup="true"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:roundIcon="@mipmap/ic_launcher_round"        android:supportsRtl="true"        android:configChanges="uiMode"        android:theme="@style/AppTheme">        <activity android:name=".MainActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application>

现在当应用程序的主题发生变化时,MainActivity并不会重新创建,而是会触发onConfigurationChanged()方法的回调,你可以在回调当中手动做一些逻辑处理。

override fun onConfigurationChanged(newConfig: Configuration) {    val currentNightMode = newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK    when (currentNightMode) {        Configuration.UI_MODE_NIGHT_NO -> {} // 夜间模式未启用,使用浅色主题        Configuration.UI_MODE_NIGHT_YES -> {} // 夜间模式启用,使用深色主题    }}

还有一点需要注意的是,切换逻辑仅在运行时生效,当我们重新启动 App 的时候,会与当前系统设置的模式保持一致。

更多相关文章

  1. Android源码设计模式分析一期发布
  2. Android启动模式:singleTask的深究--其真正含义的解读之准备工作
  3. Android(安卓)任务、进程和线程
  4. android的单例设计模式
  5. 我的android学习思维导图(1月26号)
  6. 结合Android学设计模式--开篇
  7. android与模式:解耦与复用
  8. Android(安卓)MVP模式 入门
  9. 我的太鼓达人iPhone(未启动)

随机推荐

  1. mac 无法连接android手机进行调试 解决方
  2. 可执行的android C 程序
  3. Android(安卓)简单实现Pdf
  4. Android(安卓)录音实现方法、仿微信语音
  5. cubieboard刷机
  6. AutoCompleteTextView 无限制输入字符及
  7. android:transcriptMode用法
  8. webkit里网页调用android的方法(函数)
  9. android 内核编程
  10. Android学习之Intent实现页面跳转