实现Android应用的深色模式

发布时间:2023-05-14

深色模式在 Android 应用中的实现

深色模式,也称为夜间模式或黑暗模式,具有比常规模式更低的亮度和更高的对比度。在晚上或灰暗的环境中使用深色模式可以减少眼睛疲劳,有利于保护眼睛健康。此外,深色模式还可以节省电量和延长电池寿命。因此,实现Android应用的深色模式已经是一个很有必要的功能。

一、Android的深色模式

Android 10 (API Level 29)中引入了深色主题(Dark Theme)API,让 Android 应用程序能够在日间模式和夜间模式之间进行切换,同时还支持不根据时间自动切换模式等功能。在深色模式下,Android 会应用适当的颜色主题来替换 APP 中浅色的背景和前景色。对于 Android 应用程序,只需在 res/values 下建立一个对应的 dark 文件夹,在里面建立相同的 XML 文件,然后更改 AndroidManifest.xml 中的 android:theme.

二、应用的深色模式实现

深色模式可以通过两种方式实现:手动设置和跟随系统。不同的应用程序有不同的实现方式,但大致思路都相同,通过检测系统主题的更改来触发相应的样式处理。下面提供一个简单的示例,演示如何使用 AppCompat 库实现应用的深色模式。

1. 设置主题

在 styles.xml 文件中定义一个名为 AppTheme 的主题,并继承自 AppCompat 的日间主题。然后在 styles.xml (night) 文件中定义名为 AppDarkTheme 的主题,并继承自 AppCompat 的深色主题。这样,我们就有了日间和深色两个主题。例如:

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowBackground">@color/background_light</item>
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:textColorPrimary">@color/textColorPrimaryLight</item>
        <item name="android:textColorSecondary">@color/textColorSecondaryLight</item>
    </style>
    <style name="AppDarkTheme" parent="Theme.AppCompat.NoActionBar">
        <item name="android:windowBackground">@color/background_dark</item>
        <item name="colorPrimary">@color/colorPrimaryDark</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:textColorPrimary">@color/textColorPrimaryDark</item>
        <item name="android:textColorSecondary">@color/textColorSecondaryDark</item>
    </style>
</resources>

2. 实现深色模式的开关按钮

在应用的设置界面添加一个深色模式的开关按钮。可以使用 Switch 按钮,示例如下:

<Switch
    android:id="@+id/switchDarkMode"
    android:text="@string/switch_dark_mode"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textColor="@color/colorBlack"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"/>

3. 触发深色模式

使用以下代码控制应用程序的深色模式:

switchDarkMode.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        //检测当前系统主题
        int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
        switch (currentNightMode) {
            case Configuration.UI_MODE_NIGHT_NO:
                // 切换到深色模式
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
                break;
            case Configuration.UI_MODE_NIGHT_YES:
                // 切换到日间模式
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
                break;
        }
        // 重启该Activity以生效
        recreate();
    }
});

三、结语

深色模式可以给用户带来更好的使用体验和更低的眼睛疲劳。开发人员应该考虑支持深色模式,并实现相应的切换机制。随着 Android Q 中的深色主题 API 的出现,实现 Android 应用的深色模式变得更为容易。希望这篇文章可以为你实现深色模式提供一些帮助。

完整的代码示例:

styles.xml:

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowBackground">@color/background_light</item>
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:textColorPrimary">@color/textColorPrimaryLight</item>
        <item name="android:textColorSecondary">@color/textColorSecondaryLight</item>
    </style>
</resources>

styles.xml (night):

<resources>
    <style name="AppDarkTheme" parent="Theme.AppCompat.NoActionBar">
        <item name="android:windowBackground">@color/background_dark</item>
        <item name="colorPrimary">@color/colorPrimaryDark</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:textColorPrimary">@color/textColorPrimaryDark</item>
        <item name="android:textColorSecondary">@color/textColorSecondaryDark</item>
    </style>
</resources>

主界面布局 activity_main.xml:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">
    <TextView
        android:text="@string/app_name"
        android:textAppearance="@style/TextAppearance.AppCompat.Large"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"/>
    <TextView
        android:text="@string/hello_world"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"/>
    <Switch
        android:id="@+id/switchDarkMode"
        android:text="@string/switch_dark_mode"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="@color/colorBlack"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>
</LinearLayout>

MainActivity.java:

public class MainActivity extends AppCompatActivity {
    private Switch switchDarkMode;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        switchDarkMode = findViewById(R.id.switchDarkMode);
        switchDarkMode.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //检测当前系统主题
                int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
                switch (currentNightMode) {
                    case Configuration.UI_MODE_NIGHT_NO:
                        // 切换到深色模式
                        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
                        break;
                    case Configuration.UI_MODE_NIGHT_YES:
                        // 切换到日间模式
                        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
                        break;
                }
                // 重启该Activity以生效
                recreate();
            }
        });
    }
}