今天要來寫關於Android裝置中日間/夜間主題切換的方法

Emmm在文章開始前我先說好...

這篇的重點不是要教你如何切換Android顏色配置主題ヾ(´¬`)ノ

這篇文章基本上是給工程師看的...所以如果你點進來了...也請不要急著走XD

我也會教你怎麼切黑暗主題啦(-‿◦)

 

Okay,還好留住人了(?)

咳咳回歸正題,大家有用iPhone的都知道iPhone有個所謂的深色(夜間)主題

號稱可以保護眼睛讓你在燈關掉睡覺前也能滑手機(・ωー)~☆

而深色主題長這樣

Dark mode for iPhone arrives Sept. 19: How you'll use Apple's new iOS 13  feature - CNET

 

那麼我們的Google看到此景象我們當然也不能落人於後(┼д┼;)

因此在Android系統中咱們的Android 10就有更新深色主題了!

 

其設置如下

 

打開設定


顯示

深色模式

 

基本上就完成囉

還是不知道嗎?如下圖Gif操作

 

 

咦?你跟我說找不到?

那可能你的Android手機版本不是Android10喔....

 

好,非工程師的朋友們可以拉到最底下留言按Like了XD

接下來即將進入非人類的世界(咦?)

來上一下今天的範例吧

 

因為今天要設定的東西比較複雜,所以Github在此

->https://github.com/thumbb13555/DesignModeChange/tree/master

 


 

1. 設置資料夾

 

先講講原理

 

首先來看一下資料結構

截圖 2020-11-15 上午1.30.16

 

把焦點移向res以下的資料夾

可以發現有些xml檔後面有標注(night)

截圖 2020-11-15 上午1.30.16

 

這些有標注night的檔案就是在夜間模式會用到的資源

那麼現在就來創建它吧

 

首先開啟Project資料夾檢視模式

截圖 2020-11-15 上午1.30.27

 

然後在res的資料夾下面新增drawable-night的資料夾跟values-night的資料夾

 

截圖 2020-11-15 上午1.31.13

 

再來請按照圖片中的樣子在night的資料夾內新增colors.xml以及style.xml的資料夾

然後連內容兩個的內容除了顏色以外都要一模一樣喔~往下會給程式碼

 

首先是drawable的部分,drawable的部分雖然名字一樣,但實際上是兩張不一樣的icon

 

日間模式的是太陽

 

ic_baseline_mode_24.xml

截圖 2020-11-15 下午2.20.46

<vector android:height="150dp" android:tint="#FFD738"
    android:viewportHeight="24" android:viewportWidth="24"
    android:width="150dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="@android:color/white" android:pathData="M6.76,4.84l-1.8,-1.79 -1.41,1.41 1.79,1.79 1.42,-1.41zM4,10.5L1,10.5v2h3v-2zM13,0.55h-2L11,3.5h2L13,0.55zM20.45,4.46l-1.41,-1.41 -1.79,1.79 1.41,1.41 1.79,-1.79zM17.24,18.16l1.79,1.8 1.41,-1.41 -1.8,-1.79 -1.4,1.4zM20,10.5v2h3v-2h-3zM12,5.5c-3.31,0 -6,2.69 -6,6s2.69,6 6,6 6,-2.69 6,-6 -2.69,-6 -6,-6zM11,22.45h2L13,19.5h-2v2.95zM3.55,18.54l1.41,1.41 1.79,-1.8 -1.41,-1.41 -1.79,1.8z"/>
</vector>

 

 

夜間模式的是月亮

ic_baseline_mode_24.xml

截圖 2020-11-15 下午2.21.43

<vector android:height="150dp" android:tint="#C3C3C3"
    android:viewportHeight="24" android:viewportWidth="24"
    android:width="150dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="@android:color/white" android:pathData="M11.1,12.08C8.77,7.57 10.6,3.6 11.63,2.01C6.27,2.2 1.98,6.59 1.98,12c0,0.14 0.02,0.28 0.02,0.42C2.62,12.15 3.29,12 4,12c1.66,0 3.18,0.83 4.1,2.15C9.77,14.63 11,16.17 11,18c0,1.52 -0.87,2.83 -2.12,3.51c0.98,0.32 2.03,0.5 3.11,0.5c3.5,0 6.58,-1.8 8.37,-4.52C18,17.72 13.38,16.52 11.1,12.08z"/>
    <path android:fillColor="@android:color/white" android:pathData="M7,16l-0.18,0C6.4,14.84 5.3,14 4,14c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.62,0 2.49,0 3,0c1.1,0 2,-0.9 2,-2C9,16.9 8.1,16 7,16z"/>
</vector>

 

當然,夜間模式要用的檔案就是放在-night的資料夾,稍後的顏色也是一樣

 

values的資料夾部分也是一樣

colors.xml(日)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#6200EE</color>
    <color name="colorPrimaryDark">#3700B3</color>
    <color name="colorAccent">#03DAC5</color>
    <color name="custom_color">#E8E8E8</color>
    <color name="word_color">#292929</color>
</resources>

colors.xml(夜)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="custom_color">#673AB7</color>
    <color name="word_color">#F8F8F8</color>
</resources>

style.xml(日)

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.DayNight">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>

style.xml(夜)

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="AppTheme" parent="Theme.AppCompat.DayNight">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">#FF9800</item>
        <item name="colorPrimaryDark">#FF5722</item>
        <item name="colorAccent">#8BC34A</item>

    </style>
</resources>

 

設置完後就可以切回Android資料夾檢視模式,就會看到以下樣式囉

截圖 2020-11-15 上午1.30.16

 

然後當你在設置畫面的時候,你就會看到這樣的視窗

 

截圖 2020-11-15 下午2.39.07

 

就表示設置成功了!

 

最後給你今天的介面

 

activity_main.xml

截圖 2020-11-15 下午2.40.31

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Switch
        android:id="@+id/switch1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="夜間模式切換"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="UseSwitchCompatOrMaterialXml" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toTopOf="@+id/switch1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/ic_baseline_mode_24" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="無意義的存在"
        android:backgroundTint="@color/custom_color"
        android:textColor="@color/word_color"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/switch1" />
</androidx.constraintlayout.widget.ConstraintLayout>

 


 

2. 撰寫設定儲存模組

 

目前我們已經在介面中完成了日/夜設置

接下來就是要寫程式控制它,並儲存設定的狀態

 

儲存狀態的方法我們是使用SharedPreferences的儲存機制完成它

關於SharedPreferences我之前有寫過一篇文章,可以去看看ㄜ 

->碼農日常-『Android studio』Android資料儲存-SharedPreferences的基本用法

 

那麼儲存的程式在這邊

 

SaveStatus.java

public class SaveStatus extends Application {
    public static final String NIGHT_MODE = "NIGHT_MODE";
    private boolean isNightMode = false;
    private static SaveStatus singleton = null;
    /**設置外部接口*/
    public static SaveStatus getInstance() {

        if(singleton == null)
        {
            singleton = new SaveStatus();
        }
        return singleton;
    }
    /**初始化*/
    @Override
    public void onCreate() {
        super.onCreate();
        singleton = this;
        SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
        this.isNightMode = mPrefs.getBoolean(NIGHT_MODE, false);
    }
    /**將現在的日夜間模式狀態顯示給Main傳出外部*/
    public boolean isNightMode() {
        return isNightMode;
    }
    /**設置現在使用者所選擇的日夜間狀態*/
    public void setIsNightModeEnabled(boolean isNightMode) {
        this.isNightMode = isNightMode;
        /**將現在目前的狀態存進SharedPreferences內*/
        SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
        SharedPreferences.Editor editor = mPrefs.edit();
        editor.putBoolean(NIGHT_MODE, isNightMode);
        editor.apply();
    }
}

 

然後請至AndroidManifest.xml內新增這行

 

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.jetec.designmodechange">

    <application
        android:name=".SaveStatus"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        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>

</manifest>

 


 

3. 撰寫設定

 

直接上

 

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /**從SharedPreferences中垃取目前背景色彩的設定
         * (備註:若沒有設定前,預設皆為日間模式,詳見
         * this.isNightModeEnabled = mPrefs.getBoolean(NIGHT_MODE, false);
         * 這一行)*/
        if (SaveStatus.getInstance().isNightMode()) {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
        } else {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
        }
        setContentView(R.layout.activity_main);

        @SuppressLint("UseSwitchCompatOrMaterialCode")
        Switch sw = findViewById(R.id.switch1);
        /**偵測目前的模式,如果是夜間模式的話switch設定為打開*/
        if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES){
            sw.setChecked(true);
        }

        sw.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    /**設定為夜間模式,並將設定寫入SharedPreferences*/
                    SaveStatus.getInstance().setIsNightModeEnabled(true);
                } else {
                    /**設定為日間模式,並將設定寫入SharedPreferences*/
                    SaveStatus.getInstance().setIsNightModeEnabled(false);
                }
                /**將此頁面finish掉後重新打開*/
                Intent intent = getIntent();
                intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                finish();
                startActivity(intent);
            }
        });
    }
}

 

基本上,在模式切換的時候相當於是手動將頁面重啟

整體原理就像是螢幕旋轉是一樣的概念(只是它是自動,我們是手動...)

 

所以先看向前半部

if (SaveStatus.getInstance().isNightMode()) {
    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
} else {
    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
setContentView(R.layout.activity_main);

 

這個部分就是從SharedPreferences中將前次的設定取出來

然後才再來初始化整個UI

 

最後再按下切換設定後,就把整個畫面finish掉在重啟

Intent intent = getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
startActivity(intent);

 

當然,請記得要保存狀態呦!

SaveStatus.getInstance().setIsNightModeEnabled(true);

 


 

文章就到這邊..哎呀,這禮拜好忙,這篇文到星期日才給他寫完QQ

而且週六在寫的時候,也遇到了不夠了解的地方,故障排除了一下子才給他弄完,然後又要出門...

總之..

TK

arrow
arrow
    創作者介紹
    創作者 碼農日常 的頭像
    碼農日常

    碼農日常大小事

    碼農日常 發表在 痞客邦 留言(9) 人氣()