Android應用中動態更改主題的實現


android應用程序中我們可能需要切換模式,如晚上切換到夜間模式便於閱讀等。本文參考了網上的一些資料,並結合實例,實現了動態更改主題的效果。

Android中實現theme主題可以使用在activity中使用setTheme(int)的方法,SDK中對此方法的說明為:

 

//Set the base theme for this context. Note that this should be called before any views are instantiated in the Context (for example before calling android.app.Activity.setContentView or android.view.LayoutInflater.inflate).
//需要在setcontentview函數或者inflate函數之前使用。

 

效果圖如下:

   

 

實現步驟:

首先需要定義一個屬性,此屬性用於賦值給控件的屬性,相當於控件屬性值的“變量”。

attrs.xml中,定義三個屬性,屬性的format均為reference|color

 

<resources>

    <attr name="button_bg" format="reference|color" />
    <attr name="activity_bg" format="reference|color" />
    <attr name="text_cl" format="reference|color" />

</resources>

 

接下來,在styles.xml中,編寫自定義的Theme

 

<style name="AppBaseTheme" parent="android:Theme.Light">
    </style>

    <style name="AppTheme" parent="AppBaseTheme">
        <item name="text_cl">#ffffff</item>
        <item name="button_bg">#000000</item>
        <item name="activity_bg">#ffffff</item>
    </style>

    <style name="DarkTheme" parent="AppBaseTheme">
        <item name="text_cl">#000000</item>
        <item name="button_bg">#ffffff</item>
        <item name="activity_bg">#000000</item>
</style>

 

選擇一種模式作為程序的默認theme,注意:由於我是在layout布局文件中定義的view的樣式,因此,為了保證theme切換時不會出現找不到資源的問題,因此需要在每一種用到的自定義theme中,都加上item。這里的item如text_cl和view的textColor屬性的format是一致的。

Android manifest文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testandroidsettheme"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:name="com.example.testandroidsettheme.app.MyApp"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.testandroidsettheme.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

我將android:theme="@style/AppTheme"作為默認的樣式。

 

主界面layout布局:

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?activity_bg"
    android:gravity="center"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="?button_bg"
        android:textColor="?text_cl"
        android:text="set theme" />

</LinearLayout>

 

在布局文件中,buttonbackground屬性采用的是當前theme下的button_bg的屬性值,外部的linearlayout采用的是當前theme下的activity_bg的屬性值,在填寫此屬性值時,需要在前面添加”?”,表示這是一個style中的變量。

 

在需要切換顯示不同themeactivity中,一些博客中在button點擊事件中使用

setTheme(int);

recreate();

的方式,我發現此種方式無法實現theme的切換,因為recreate()方法會重新創建此activity,之前的setTheme()無效。我的實現方式如下:

 

public class MainActivity extends Activity {

    public Button button0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MyApp app = (MyApp)MainActivity.this.getApplication();
        if(app.theme == 0){
            //使用默認主題
        }else{
            //使用自定義的主題
            setTheme(app.theme);
        }
        setContentView(R.layout.activity_main);

        button0 = (Button) this.findViewById(R.id.button0);
        button0.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MyApp app = (MyApp)MainActivity.this.getApplication();
                app.theme = R.style.DarkTheme;
                recreate();
            }
        });
    }
}

public class MyApp extends Application{
    public int theme = 0;
}

 

在此activityoncreate()中的setContentView()方法調用之前,判斷當前的theme,並調用setTheme(),實現改變theme的效果。

注意:這種方法實現切換theme不是很友好,因為在activity重新創建時,可能會有閃屏的現象。比較好的解決方案如知乎客戶端采用的是截屏,並漸隱圖片的過度方式,具體的實現還有待學習。

 

參考資料:http://www.kymjs.com/code/2015/05/26/01/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM