2012-01-10 43 views
22

我想讓用戶在幾個不同的主題之間進行選擇,並想知道這是否是一種正確的做事方式。我用這種方法做了一些測試,結果很有效,但我認爲可能有更好的方法,並認爲它可能會在以後引起一些問題,所以想問一下。實現用戶選擇主題

我正在考慮爲每個主題創建不同的佈局,並且在onCreate中只有setContentView()方法的開關。我會首先加載一個已保存的SharedPreference值(整數),並取決於該值顯示的是相應的佈局。顯然,用戶可以用按鈕或其他來改變SharedPreference的值。

由於這些佈局基本相同,但顏色不同,所以我想在每個佈局文件中爲我的TextViews和其他視圖使用相同的ID。我的主要問題是會造成問題嗎?

對不起,沒有代碼的文本牆。我只想爲這種情況得到一個良好實踐的總體思路。提前致謝。

回答

37

我實際上在我的應用程序中有此功能,另外,我允許用戶在運行時更改主題。由於從首選項中讀取值需要一些時間,我通過全局可訪問的函數獲取主題ID,該函數保存緩存的值。

正如已經指出的 - 使用this guide創建一些Android主題。您的styles.xml文件中至少有兩個<style>項目。例如:

<style name="Theme.App.Light" parent="@style/Theme.Light">...</style> 
<style name="Theme.App.Dark" parent="@style/Theme">...</style> 

現在,您必須將其中一種樣式應用於您的活動。我在活動中的的onCreate方法這樣做,任何其他調用之前:

setTheme(MyApplication.getThemeId()); 

getThemeId是返回緩存主題ID的方法:

public static int getThemeId() 
{ 
    return themeId; 
} 

該領域正被另一個方法更新:

public static void reloadTheme() 
{ 
    themeSetting = PreferenceManager.getDefaultSharedPreferences(context).getString("defaultTheme", "0"); 
    if(themeSetting.equals("0")) 
     themeId = R.style.Theme_Light; 
    else 
     themeId = R.style.Theme_Dark; 
} 

每當首選項被改變時(以及當然啓動時),都會調用它。這兩種方法存在於MyApplication類中,該類擴展了Application。首選項更改偵聽器在本文後面描述,並駐留在主活動類中。

最後一個也是非常重要的事情 - 主題適用於活動開始時。假設,只能在首選項屏幕上更改主題,並且只有一種方法可以實現,即只有一個(主要)活動,當您退出首選項屏幕時,此活動不會重新啓動 - 舊主題仍然會用過的。下面是該修復(重新啓動您的主要活動):

@Override 
protected void onResume() { 
    super.onResume(); 
    if(schduledRestart) 
    { 
     schduledRestart = false; 
     Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName()); 
     i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
     startActivity(i); 
    } 
} 

scheduledRestart是一個布爾變量,最初設置爲false。它設置爲true時,主題是由這個監聽器,這也更新之前提到的緩存主題ID改爲:

private class themeListener implements OnSharedPreferenceChangeListener{ 

    @Override 
    public void onSharedPreferenceChanged(SharedPreferences spref, String key) { 
     if(key.equals("defaultTheme") && !spref.getString(key, "0").equals(MyApplication.getThemeSetting())) 
     { 
      MyApplication.reloadTheme(); 
      schduledRestart = true; 
     } 
    } 


sp = PreferenceManager.getDefaultSharedPreferences(this); 

listener = new themeListener(); 
sp.registerOnSharedPreferenceChangeListener(listener); 

記住要堅持監聽對象的引用,否則會被垃圾colleted(和將停止工作)。

+0

非常好的答案,非常感謝! – 2012-01-10 23:18:16

+0

我以爲我可以在不擴展應用程序的情況下解決問題,但問題是getApplicationInfo()。theme不會更新,如果我執行getApplication()。setTheme(myThemeId)'...所以是的,你的方法是正確的。 – vault 2013-01-25 17:21:49

+1

現在看起來有一個更簡單的重新開始活動的方法:'重新創建'(https://developer.android.com/reference/android/app/Activity.html#recreate%28%29)。 – BlueMonkMN 2018-01-27 17:45:59

2

這樣做,如果你這樣做,我不認爲這會導致任何問題,但它看起來像很多麻煩(你必須乘以所有你想添加的主題的所有佈局。如果以後你想修改某個佈局中的資源,則必須在所有主題中進行修改。)

爲什麼不使用Android的Styles and Themes功能?

它們可以應用到整個活動輕鬆:

<activity android:theme="@style/my_theme"> 

所以,當你在SharedPreferences值檢測的改變你使用(上偏好活動按鈕,或某事),你只需切換風格。或者更好的是,您可以設置樣式以在運行時(創建活動時)讀取您的首選項值,並相應地應用正確的樣式/主題。

+0

我將閱讀「樣式和主題」功能並嘗試這樣做,謝謝你的信息。會在一小時內讓你滿意,因爲我昨天用完了它們:P – 2012-01-10 23:02:17

2

您也可以使用動態改變主題:

ContextThemeWrapper w = new ContextThemeWrapper(this, <newTHEMEId>); 
getTheme().setTo(w.getTheme()); 

之前的onCreate每一項活動。