Android夜間模式官方api實現(AppCompatDelegate)

Android夜間模式官方api實現(AppCompatDelegate)

Android夜間模式能夠經過手動設置不一樣的Theme來實現,也有第三方框架可拿來用,Api 23.0.0後能夠使用AppCompatDelegate來實現夜間模式切換,效果:java

圖片描述

首先咱們須要在style(res/values/style.xml)中生成咱們須要主題:android

<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>

這裏的主題繼承了Theme.AppCompat.DayNight,這個主題是一個family,還包含一些額外的主題:
Theme.AppCompat.DayNight.DarkActionBar、Theme.AppCompat.DayNight.NoActionBar等等.均可以使用在夜間模式中.一個夜間,一個白天,顯然須要兩套資源方案,這裏設置的只是日間模式(不知道這個表達對不對)下的主題,包括顏色也是日間模式所須要的(/res/values/colors.xml):api

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>

    <color name="textColor">#f45d5d</color>
</resources>

接下來須要提供一套夜間模式的資源,能夠在/res/下生成一個values-night資源文件夾,
當使用代碼設置夜間模式時,系統會自動引用這個文件夾下的資源.該文件夾下的資源文件名和/res/values/中的文件名保持一致,包括資源Id也需一致,以下:app

/res/values-night/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>

/res/values-night/color.xml:ide

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#141212</color>
    <color name="colorPrimaryDark">#423737</color>
    <color name="colorAccent">#2e41ea</color>
    <color name="textColor">#4861ea</color>
</resources>

其餘資源文件的設置也是如此,系統會在特定的模式下,自動識別,這裏的顏色我是本身配置的,其實更好的方式是使用系統自帶的顏色方案:?android:attr/textColor、?android:attr/textColorPrimary等,避免本身配置的顏色不統一,好比文字顏色和背景色相近,文字就看不清楚了,接下來就是代碼的動態設置。佈局

AppCompatDelegate:ui

AppCompatDelegate有四種模式能夠設置:spa

MODE_NIGHT_YES:直接指定夜間模式code

MODE_NIGHT_NO:直接指定日間模式

MODE_NIGHT_FOLLOW_SYSTEM:根據系統設置決定是否設置夜間模式

MODE_NIGHT_AUTO:根據當前時間自動切換模式

若是要在app啓動的時候就設置夜間模式,能夠將代碼寫在Application中:

public class MyApplication extends Application {

    //也能夠直接使用代碼塊直接設置
    //static {
     //AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_ NIGHT_YES);
    //}
    @Override
    public void onCreate() {
        super.onCreate();

        //根據app上次退出的狀態來判斷是否須要設置夜間模式,提早在SharedPreference中存了一個是不是夜間模式的boolean值
        boolean isNightMode = NightModeConfig.getInstance().getNightMode(getApplicationContext());
        if (isNightMode) {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
        }else {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
        }
    }
}

通常咱們都是給用戶提供一個選項來選擇是否要啓用夜間模式,寫一個Activity,提供設置功能,佈局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/tv_message"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="50dp"
        android:gravity="center"
        android:layout_alignParentLeft="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="個人消息"
        android:textColor="@color/colorAccent"
        android:textSize="25sp"/>

    <TextView
        android:id="@+id/tv_book"
        android:layout_alignLeft="@id/tv_message"
        android:layout_below="@id/tv_message"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="50dp"
        android:gravity="center"
        android:layout_alignParentLeft="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/colorAccent"
        android:text="個人書籍"
        android:textSize="25sp"/>

    <TextView
        android:id="@+id/tv_money"
        android:layout_alignLeft="@id/tv_message"
        android:layout_below="@id/tv_book"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="50dp"
        android:gravity="center"
        android:layout_alignParentLeft="true"
        android:layout_width="wrap_content"
        android:textColor="@color/colorAccent"
        android:layout_height="wrap_content"
        android:text="個人金幣"
        android:textSize="25sp"/>

    <TextView
        android:id="@+id/tv_market"
        android:layout_alignLeft="@id/tv_message"
        android:layout_below="@id/tv_money"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="50dp"
        android:gravity="center"
        android:layout_alignParentLeft="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/colorAccent"
        android:text="圖書市場"
        android:textSize="25sp"/>

    <RelativeLayout
        android:layout_alignLeft="@id/tv_message"
        android:layout_below="@id/tv_market"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp">
        <TextView
            android:id="@+id/tv_mode"
            android:gravity="center"
            android:layout_alignParentLeft="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="夜間模式"
            android:textColor="@color/colorAccent"
            android:textSize="25sp"/>

    </RelativeLayout>
</RelativeLayout>

代碼設置,點擊文字"夜間模式"的時顯示效果

package com.example.why.traing2;

import android.content.Intent;
import android.content.res.Configuration;
import android.support.v4.text.TextDirectionHeuristicCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.app.AppCompatDelegate;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class FirstActivity extends AppCompatActivity {

    private TextView mNightModeTv;
    private Button mNextBtn;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);

        //AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);,若是直接在onCreate()中調用,FirstActivity直接生效,無需調用recreate()
        mNextBtn = (Button)findViewById(R.id.btn_next);

        mNightModeTv = (TextView)findViewById(R.id.tv_mode);

        mNightModeTv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //獲取當前的模式,設置相反的模式,這裏只使用了,夜間和非夜間模式
                int currentMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
                if (currentMode != Configuration.UI_MODE_NIGHT_YES) {
                   //保存夜間模式狀態,Application中能夠根據這個值判斷是否設置夜間模式
                    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);

                    //ThemeConfig主題配置,這裏只是保存了是不是夜間模式的boolean值
                    NightModeConfig.getInstance().setNightMode(getApplicationContext(),true);
                } else {
                    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
                    NightModeConfig.getInstance().setNightMode(getApplicationContext(),false);
                }

                recreate();//須要recreate才能生效
            }
        });

    }
}

currentMode取值:

int currentNightMode = getResources().getConfiguration().uiMode
        & Configuration.UI_MODE_NIGHT_MASK;
switch (currentNightMode) {
    case Configuration.UI_MODE_NIGHT_NO://夜間模式未啓用
    case Configuration.UI_MODE_NIGHT_YES://夜間模式啓用
    case Configuration.UI_MODE_NIGHT_UNDEFINED://不肯定是哪一種模式,假設不是夜間模式
}
package com.example.why.traing2;

import android.content.Context;
import android.content.SharedPreferences;

public class NightModeConfig {
    private SharedPreferences mSharedPreference;
    private static final String NIGHT_MODE = "Night_Mode";
    public static final String IS_NIGHT_MODE = "Is_Night_Mode";

    private boolean mIsNightMode;

    private  SharedPreferences.Editor mEditor;

    private static NightModeConfig sModeConfig;

    public static NightModeConfig getInstance(){

        return sModeConfig !=null?sModeConfig : new NightModeConfig();
    }

    public boolean getNightMode(Context context){

        if (mSharedPreference == null) {
            mSharedPreference = context.getSharedPreferences(NIGHT_MODE,context.MODE_PRIVATE);
        }
        mIsNightMode = mSharedPreference.getBoolean(IS_NIGHT_MODE, false);
        return mIsNightMode;
    }

    public void setNightMode(Context context, boolean isNightMode){
        if (mSharedPreference == null) {
            mSharedPreference = context.getSharedPreferences(NIGHT_MODE,context.MODE_PRIVATE);
        }
        mEditor = mSharedPreference.edit();

        mEditor.putBoolean(IS_NIGHT_MODE,isNightMode);
        mEditor.commit();
    }
}

這樣就能夠根據用戶的喜愛來設置是否啓用夜間模式,注意點:

  1. AppCompatDelegate類中還有一個方法:setLocalNightMode(int mode),這個方法做用在當前組件,Activity中使用 getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES)設置。好比在Application中設置爲日間模式,而在當前Activity中調用getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES),該Activity會顯示爲夜間模式,覆蓋原來的模式。
  2. AppCompatDelegate.setDefaultNightMode(int mode);只做用於新生成的組件,對原先處於任務棧中的Activity不起做用。若是直接在Activity的onCreate()中調用這句代碼,那當前的Activity中直接生效,不須要再調用recreate(),但咱們一般是在監聽器中調用這句代碼,那就須要調用recreate(),不然對當前Activity無效(新生成的Activity仍是生效的)。固然能夠提早在onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState)中保存好相關屬性值,重建時使用。

參考:
https://medium.com/@chrisbane...

http://wuxiaolong.me/2016/07/...

相關文章
相關標籤/搜索