Android夜間模式初探

當下各種閱讀類APP(如各種瀏覽器,某日頭條等)都會有夜間模式,也順應了大家的睡前必須玩一下手機的作息習慣。關於夜間模式的實現,有很多種方法。這篇日誌學習一下最簡單的實現方式,通過setTheme(int resid)方法實現主題切換來實現夜間模式,這也是Android官方推薦的方法。

整體思路與效果

通過Android SDK提供的setTheme方法,可以切換Activity的不同的主題,這樣定義一個合適的主題,就可以實現夜間模式了。

首先看一下效果圖

主題切換效果圖

定義不同的主題

自定義主題屬性

<resources>
    <attr name="textColorValue" format="color" />
      ...
</resources>

這裏我們可以定義一些切換時,需要更改的內容屬性。比如說,當前頁面中所有文字的顏色,在平時是黑色,在夜間模式是灰色,那麼可以在這裏定義一個屬性,在自定義主題時設置不同的顏色即可。

自定義不同的主題

<!--日間模式主題-->
    <style name="CustomThemeLight" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/light</item>
        <item name="colorPrimaryDark">@color/light</item>
        <item name="colorAccent">@color/black</item>
        <item name="android:textColorPrimary">@color/black</item>
        <item name="android:windowBackground">@color/white</item>
        <item name="textContent">@string/theme0</item>
        <item name="textColorValue">@color/black</item>
        <item name="pupwindowTheme">@style/AppTheme.PopupLight</item>
    </style>


    <!--夜間模式主題-->
    <style name="CustomThemeDark" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/dark_bg</item>
        <item name="colorPrimaryDark">@color/dark_bg</item>
        <item name="colorAccent">@color/dark_bg</item>
        <item name="android:windowBackground">@color/dark_bg</item>
        <item name="textContent">@string/theme1</item>
        <item name="textColorValue">@color/white</item>
        <item name="pupwindowTheme">@style/AppTheme.PopupDark</item>
    </style>

熟悉ToolBar的同學,應該對上面幾個屬性不陌生。這裏首先設置了colorPrimary,colorPrimaryDark,windowBackground等幾個屬性,首先確定了這個主題整體的色調

接下來就上對自定義屬性的設置,這裏我們可以看到在textColorValue的屬性在日間模式和夜間模式中分別設置成了黑色和白色。

自定義屬性的使用

接下來,就是將自定義屬性作用到佈局文件中

<RelativeLayout
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="10dp"
            android:padding="10dp"
            android:text="公開文章"
            android:textColor="?attr/textColorValue"
            android:textSize="16sp" />


        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginRight="10dp"
            android:drawablePadding="10dp"
            android:drawableRight="@mipmap/right_arrow"
            android:gravity="center_vertical"
            android:padding="10dp"
            android:text="11"
            android:textColor="?attr/textColorValue" />
    </RelativeLayout>

如上面這段代碼所示,你可以將應用中所有TextView的TextColor的屬性設置爲?attr/textColorValue,這樣他的值就會根據你在自定義主題中所設定的值變化。這樣是不是比通過java代碼寫一大串if-else方便許多呢。

到這裏你應該想到了,在自定義屬性時可以定義各種各樣的內容,TextView的大小,ImageView的大小,LinearLayout的背景等等。雖然這樣在一開始寫代碼的時候有些繁瑣,但從長遠來說,是很有價值的。

主題切換

這裏首先需要明確一點,setTheme方法必須在setContentView方法之前執行,纔會有效(這個有點讓人失望,但想想也是必然的),所以呢,採用這種方式實現夜間模式,Activity必然需要重啓,因此這裏需要考慮到Activity切換的問題,不能讓人覺得換了一個夜間模式,整個應用重啓了一遍,那也太low了。

Activity切換效果

activity.finish();        activity.overridePendingTransition(R.anim.fade_in, R.anim.fade_out);

這裏只需定義兩個動畫效果,確保Activity切換效果不明顯即可,採用alpha動畫即可,這裏就不再贅述。

主題切換實現

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this;
        Util.onActivityCreateSetTheme(this);
        setContentView(R.layout.activity_main);       
    }

這裏我們在setContentView方法之前調用setTheme方法

主題切換工具類util

    public static void onActivityCreateSetTheme(Activity activity) {
        switch (sTheme) {
            case Constants.THEME_DARK:               activity.setTheme(R.style.CustomThemeDark);
                break;                           
            case Constants.THEME_LIGHT:               activity.setTheme(R.style.CustomThemeLight);
                break;
            default:
                break;

        }
    }

這樣就爲當前Activity設置了相應的主題。

調用下面的方法,傳入不同的主題id即可實現主題切換

 public static void changeToTheme(Activity activity, int theme) {
        sTheme = theme;
        activity.finish();
        activity.overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
        activity.startActivity(new Intent(activity, activity.getClass()));
    }

好了,這裏就是關於夜間模式的簡單瞭解。這種方式,相對來說比較繁瑣,但也最容易理解。當然,這裏只是從最簡單的角度出發,沒有考慮Activity重啓前後數據保存和恢復的問題,以及對Fragment的影響等問題,實際問題還是需要根據實際項目分析,這裏就不展開來說。

這裏對於自定義屬性和主題的用法,還是值得借鑑,即便不一定要用到夜間模式,當時通過切換主題實現UI的更新也是一種考慮。

完整代碼已上傳到github,有興趣的同學可以參考一下。

github代碼地址


發佈了47 篇原創文章 · 獲贊 23 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章