一種簡單快速的方式實現 Android App 的夜間模式

博主聲明:

轉載請在開頭附加本文鏈接及作者信息,並標記爲轉載。本文由博主 威威喵 原創,請多支持與指教。

本文首發於此   博主威威喵  |  博客主頁https://blog.csdn.net/smile_running

在現在的很多應用中,都有一個夜間模式,由於大部分人玩手機都到深更半夜,白色的主題在夜晚不開燈的情況下,顯得屏幕非常亮。一種辦法是降低屏幕的亮度,就比如我的手機一般都開起了自動亮度的功能;還有一種辦法就是將 App 切換到夜間模式,其實就是改變一下主題顏色。

在 Android support v7 包版本 23 及以後,系統就提供了一種簡單而快速的方式,讓我們得以很快的切換到夜間模式。接下來,通過一個案例來實現一下。

首先呢,我們建立一個空項目即可,但需要加入兩個 package,如下:

相對應的,必須命名爲 drawable-night 和 values-night

我們項目默認的主題顏色,也就是日間模式,如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#008577</color>
    <color name="colorPrimaryDark">#00574B</color>
    <color name="colorAccent">#D81B60</color>

    <color name="colorCommonText">#5CACEE</color>
    <color name="colorPressedBtnBg">#FF00FF</color>
    <color name="colorCommonBtnBg">#CFCFCF</color>
</resources>

夜間模式,顏色需要換成黑色或深色,比較護眼吧

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#4F4F4F</color>
    <color name="colorPrimaryDark">#363636</color>
    <color name="colorAccent">#828282</color>

    <color name="colorCommonText">#66FF99</color>
    <color name="colorPressedBtnBg">#00FFFF</color>
    <color name="colorCommonBtnBg">#708090</color>
</resources>

以上是 values package 的日間 / 夜間模式的適配,如果在 View 中還有引用到 drawable package 的話,也要做對應的處理。例如,給一個 Button 換樣式,日間模式的樣式代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/colorPressedBtnBg" android:state_pressed="true" />
    <item android:drawable="@color/colorCommonBtnBg" android:state_pressed="false" />
</selector>

夜間模式,同樣需要

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/colorPressedBtnBg" android:state_pressed="true" />
    <item android:drawable="@color/colorCommonBtnBg" android:state_pressed="false" />
</selector>

到此,差不多就完成了一半。

接下來,就是使用代碼去控制日間和夜間兩種模式的切換效果了。一般的,這個切換行爲是一個 Switch 開關,它的用法其實就和 CheckBox 一樣,設置選中狀態的變化監聽即可。以下是 MainActivity 裏的代碼:

public class MainActivity extends AppCompatActivity {

    private SharedPreferences mSharedPreferences;
    private Switch sw_night_mode;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        sw_night_mode = (Switch) findViewById(R.id.sw_night_mode);
        mSharedPreferences = getSharedPreferences("app_night_mode", MODE_PRIVATE);

        boolean isNightMode = mSharedPreferences.getBoolean("night_mode", false);
        if (isNightMode) {
            sw_night_mode.setChecked(true);
        } else {
            sw_night_mode.setChecked(false);
        }

        sw_night_mode.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked && !isNightMode) {
                    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
                    mSharedPreferences.edit().putBoolean("night_mode", true).apply();
                } else if (!isChecked && isNightMode) {
                    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
                    mSharedPreferences.edit().putBoolean("night_mode", false).apply();
                }
                startActivity(new Intent(MainActivity.this, MainActivity.class));
                overridePendingTransition(R.anim.night_mode_open_anim, R.anim.night_mode_close_anim);
                finish();
            }
        });

    }
}

這裏需要注意的一個點:因爲我們在切換模式之後,需要先關閉當前 Activity,然後啓動它。這個過程需要保存一下 Switch 被選中的狀態,否則每一次打開 Activity 的時候,都默認沒有被選中,就會造成切換不回來日間模式的問題。

還有一個問題,就是 Activity finish 了,然後在 start 會有一點生硬,這個可以用過渡動畫來解決,一個是打開 Activity 動畫:

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromAlpha="0"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:toAlpha="1.0" />

關閉 Activity 的動畫:

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromAlpha="1.0"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:toAlpha="0" />

這裏也需要注意一點,overridePedingTransition() 方法需要在 startActivity 之後調用,否則動畫沒有效果。

最後,來看看效果吧

到此爲止,就搞定了一個簡單快速夜間模式切換了。

如果需要保存當前的夜間模式,上面的操作是無法進行保存的,如果 App 被殺死的話,下次再進入則還是日間模式。所以,在 Activity 的 onCreate 方法之前,就應該去判斷一下當前的模式,代碼如下:

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        mSharedPreferences = getSharedPreferences("app_night_mode", Context.MODE_PRIVATE);
        if (mSharedPreferences.getBoolean("night_mode", false)) {
            getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
        } else {
            getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_NO);
        }
        super.onCreate(savedInstanceState);

    }

這樣的話,就會還原用戶上一次保存的模式了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章