2010-03-20 19 views
121

Ich habe eine PreferenceActivity erstellt, mit der der Benutzer das Thema auswählen kann, das er auf die gesamte Anwendung anwenden möchte.So ändern Sie das aktuelle Design zur Laufzeit in Android

Wenn der Benutzer ein Thema auswählt, wird dieser Code ausgeführt:

if (...) { 
    getApplication().setTheme(R.style.BlackTheme); 
} else { 
    getApplication().setTheme(R.style.LightTheme); 
} 

Aber, obwohl ich mit dem Debugger überprüft haben, dass der Code ausgeführt wird, kann ich sehen, keine Änderung in der Benutzeroberfläche.

Themen sind in res/values/styles.xml definiert, und Eclipse zeigt keinen Fehler an.

<resources> 
    <style name="LightTheme" parent="@android:style/Theme.Light"> 
    </style> 

    <style name="BlackTheme" parent="@android:style/Theme.Black"> 
    </style>  
</resources> 

Irgendeine Idee darüber, was passieren könnte und wie man es beheben kann? Sollte ich an einem bestimmten Punkt im Code setTheme anrufen? Meine Anwendung besteht aus mehreren Aktivitäten, wenn das hilft.

+0

http://stackoverflow.com/a/32111974/1318946 –

Antwort

67

Ich möchte die Methode auch sehen, wo Sie einmal für alle Ihre Aktivitäten festgelegt. Aber soweit ich weiß, müssen Sie in jeder Aktivität einstellen, bevor Sie irgendwelche Ansichten zeigen.

Für Referenz-Check this:

http://www.anddev.org/applying_a_theme_to_your_application-t817.html

Edit (aus diesem Forum kopiert):

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    // Call setTheme before creation of any(!) View. 
    setTheme(android.R.style.Theme_Dark); 

    // ... 
    setContentView(R.layout.main); 
} 
+2

Es funktioniert, aber Änderungen werden nicht angewendet, bis Sie nicht von einer Aktivität zu einer anderen wechseln ... –

+4

das ist, weil nach der Dokumentation (die Sie wirklich sollten bedenke das Lesen, viele coole Sachen darin) "dies sollte aufgerufen werden, bevor irgendwelche Ansichten im Kontext instanziiert werden" (in http://developer.android.com/reference/android/view/ContextThemeWrapper.html#setTheme%28int% 29) – njzk2

+12

Bitte geben Sie eine unabhängige Antwort, so dass, wenn dieser Link stirbt Menschen immer noch Zugriff auf Ihre Antwort haben –

1

Sie können die Akivität beenden und neu erstellen anschließend auf diese Weise wird Ihre Aktivität erstellt werden wieder und alle Ansichten werden mit dem neuen Thema erstellt.

9

Wir haben Thema zu setzen, bevor 'super.onCreate()' und 'setContentView()' Methode aufrufen.

Schauen Sie sich link an, um ein neues Design zur Laufzeit auf die gesamte Anwendung anzuwenden.

+0

Offenbar bedeutet dies "vor dem Aufruf * super.onCreate() * und setContentView()." BTW Ich habe diese Antwort früher abgelehnt, weil es falsch schien; Jetzt verstehe ich, was gemeint war, und ich sehe darin einen Wert (obwohl es nicht klar ausgesprochen wurde). Ich kann meine Stimme jedoch nicht ändern, wenn die Antwort nicht bearbeitet wird. Wenn das passiert, benachrichtigen Sie mich bitte, damit ich meine Stimme ändern kann. – LarsH

+0

@LarsH ha ha ha Keine Probleme liebes. –

+1

Ich habe es bearbeitet und den Downvote entfernt. – LarsH

15

Ich habe das gleiche Problem, aber ich fand die Lösung.

public class EditTextSmartPhoneActivity extends Activity implements DialogInterface.OnClickListener 
{ 
    public final static int CREATE_DIALOG = -1; 
    public final static int THEME_HOLO_LIGHT = 0; 
    public final static int THEME_BLACK = 1; 

    int position; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) 
    { 
     position = getIntent().getIntExtra("position", -1); 

     switch(position) 
     { 
     case CREATE_DIALOG: 
      createDialog(); 
      break; 
     case THEME_HOLO_LIGHT: 
      setTheme(android.R.style.Theme_Holo_Light); 
      break; 
     case THEME_BLACK: 
      setTheme(android.R.style.Theme_Black); 
      break; 
     default: 
     } 

     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

    } 

    private void createDialog() 
    { 
     /** Options for user to select*/ 
     String choose[] = {"Theme_Holo_Light","Theme_Black"}; 

     AlertDialog.Builder b = new AlertDialog.Builder(this); 

     /** Setting a title for the window */ 
     b.setTitle("Choose your Application Theme"); 

     /** Setting items to the alert dialog */ 
     b.setSingleChoiceItems(choose, 0, null); 

     /** Setting a positive button and its listener */ 
     b.setPositiveButton("OK",this); 

     /** Setting a positive button and its listener */ 
     b.setNegativeButton("Cancel", null); 

     /** Creating the alert dialog window using the builder class */ 
     AlertDialog d = b.create(); 

     /** show dialog*/ 
     d.show(); 
    } 

    @Override 
    public void onClick(DialogInterface dialog, int which) { 
     // TODO Auto-generated method stub 
     AlertDialog alert = (AlertDialog)dialog; 
     int position = alert.getListView().getCheckedItemPosition(); 

     finish(); 
     Intent intent = new Intent(this, EditTextSmartPhoneActivity.class); 
     intent.putExtra("position", position); 
     intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
     intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
     startActivity(intent); 
    } 
} 
+3

Dies ist, wenn Sie Benutzer zur Laufzeit ein Thema auswählen möchten. Keine Notwendigkeit, in Manifest festlegen – Unknown

+0

Dies funktioniert. Ich habe es mit einer sharedpreferences-Konfiguration gekoppelt, so dass die Änderung des Themas dauerhaft ist. – pandalion98

+2

ist der Aufruf von 'super.onCreate()' nach 'setTheme()' auch kritisch, um dies zu funktionieren? Ich hatte den Eindruck, dass man 'setTheme()' aufrufen muss, bevor man 'setContentView()' aufruft. –

43

Wenn Sie Thema einer bereits bestehenden Aktivitäten ändern möchten, rufen Sie recreate() nach setTheme().

Hinweis: Rufen Sie nicht erneut auf, wenn Sie das Thema in onCreate() ändern, um Endlosschleife zu vermeiden.

+1

Diese Antwort wäre nützlicher, wenn sie einige Beweise oder Begründungen zitiert, um zu erklären, warum es notwendig ist, 'recreate() aufzurufen. ', obwohl die Dokumentation (http://developer.android.com/reference/android/content/Context.html#setTheme(int)) nur zu' setTheme() 'sagt, bevor irgendwelche Ansichten instanziiert werden. Wollen Sie recreate() nur dann aufrufen, wenn bereits Ansichten instanziiert wurden? – LarsH

+3

Insbesondere wenn Sie 'setTheme()' in Ihrem 'onCreate()' aufrufen, müssen Sie vor dem Aufruf von super.onCreate() oder setContentView() (1) prüfen, ob Sie sich gegen eine Endlosschleife schützen wo du immer wieder bildest; und (2) was hast du überhaupt gewonnen? – LarsH

7

Ich hatte ein ähnliches Problem, und ich auf diese Weise gelöst ..

@Override 
public void onCreate(Bundle savedInstanceState) { 

    if (getIntent().hasExtra("bundle") && savedInstanceState==null){ 
     savedInstanceState = getIntent().getExtras().getBundle("bundle"); 
    } 

    //add code for theme 

    switch(theme) 
    { 
    case LIGHT: 
     setTheme(R.style.LightTheme); 
     break; 
    case BLACK: 
     setTheme(R.style.BlackTheme); 
     break; 

    default: 
    } 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    //code 

} 

dieser Code für recreate ist die Aktivität Bundle speichern und das Thema zu ändern. Sie müssen Ihren eigenen onSaveInstanceState (Bundle outState) schreiben; Von API-11 können Sie die Methode recreate() verwenden, anstatt

Bundle temp_bundle = new Bundle(); 
onSaveInstanceState(temp_bundle); 
Intent intent = new Intent(this, MainActivity.class); 
intent.putExtra("bundle", temp_bundle); 
startActivity(intent); 
finish(); 
17

recreate() (wie TPReal erwähnt) nur aktuelle Aktivität neu zu starten, aber die bisherigen Aktivitäten werden nach wie vor in zurück Stapel und Thema sein wird, nicht angewendet werden Sie.

also eine andere Lösung für dieses Problem ist die Aufgabe Stapel vollständig, wie dies neu:

TaskStackBuilder.create(getActivity()) 
      .addNextIntent(new Intent(getActivity(), MainActivity.class)) 
      .addNextIntent(getActivity().getIntent()) 
      .startActivities(); 

EDIT:

einfach den Code setzen oben, nachdem Sie führen auf der Benutzeroberfläche des Themas zu ändern oder irgendwo anders. Alle Ihre Aktivitäten sollten die Methode setTheme() vor onCreate() aufgerufen haben, wahrscheinlich in einer übergeordneten Aktivität. Es ist auch ein normaler Ansatz, das in SharedPreferences gewählte Thema zu speichern, zu lesen und dann unter Verwendung der Methode setTheme() einzustellen.

+0

Wo würdest du diesen Code ablegen? Wenn Sie es in Activity.onCreate() einfügen, führt das zu einer Endlosschleife? – LarsH

+0

Fügen Sie diesen Code einfach ein, nachdem Sie das Thema auf der Benutzeroberfläche oder anderswo geändert haben. Für alle Ihre Aktivitäten sollte die Methode 'setTheme()' vor 'onCreate() 'aufgerufen werden, wahrscheinlich in einer übergeordneten Aktivität. –

+0

Vielen Dank für Ihre Geduld, während ich versuche, dies zu verstehen. Mit "Elternaktivität" meine ich die Aktivität, die (mit 'startActivity()') die Aktivität gestartet hat, deren Thema ich ändern möchte. – LarsH

2

Dies ist, was ich für Material Design erstellt habe. Möge es dir behilflich sein.

Werfen Sie einen Blick für MultipleThemeMaterialDesign

2

Ich weiß, dass ich bin spät, aber ich würde eine Lösung wie hier posten: here den vollständigen Quellcode prüfen. Dies ist der Code, den ich verwendet, wenn Thema Vorlieben mit wechselnden ..

SharedPreferences pref = PreferenceManager 
     .getDefaultSharedPreferences(this); 
String themeName = pref.getString("prefSyncFrequency3", "Theme1"); 
if (themeName.equals("Africa")) { 
    setTheme(R.style.AppTheme); 
} else if (themeName.equals("Colorful Beach")) { 
    //Toast.makeText(this, "set theme", Toast.LENGTH_SHORT).show(); 
    setTheme(R.style.beach); 
} else if (themeName.equals("Abstract")) { 
    //Toast.makeText(this, "set theme", Toast.LENGTH_SHORT).show(); 
    setTheme(R.style.abstract2); 
} else if (themeName.equals("Default")) { 
    setTheme(R.style.defaulttheme); 
} 
2

Statt

getApplication().setTheme(R.style.BlackTheme); 

Verwendung

setTheme(R.style.BlackTheme); 

Mein Code: in onCreate() Methode:

super.onCreate(savedInstanceState); 

if(someExpression) { 
    setTheme(R.style.OneTheme); 
} else { 
    setTheme(R.style.AnotherTheme); 
} 

setContentView(R.layout.activity_some_layout); 

Irgendwo (zum Beispiel auf eine Schaltfläche klicken):

YourActivity.this.recreate(); 

Sie haben Aktivität zu erstellen, andernfalls - Änderung nicht

0

Anruf SetContentView (Resource.Layout.Main) nach setTheme() passieren wird.

0

Dies hatte keinen Effekt für mich:

public void changeTheme(int newTheme) { 
    setTheme(newTheme); 
    recreate(); 
} 

Aber das funktionierte:

int theme = R.style.default; 

protected void onCreate(Bundle savedInstanceState) { 
    setTheme(this.theme); 
    super.onCreate(savedInstanceState); 
} 

public void changeTheme(int newTheme) { 
    this.theme = newTheme; 
    recreate(); 
} 
+0

Entsprechend Ihrem Code setzen Sie das Thema auf eine Variable, die nie verwendet wird. Ich glaube, das setTheme in onCreate sollte '' '' Theme (theme); '' 'gesetzt werden – LoungeKatt

2

Auf diese Weise Arbeit für mich:

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    setTheme(GApplication.getInstance().getTheme()); 
    super.onCreate(savedInstanceState); 

    setContentView(R.layout.activity_main); 
} 

Dann sind Sie ein neues Thema ändern möchten :

GApplication.getInstance().setTheme(R.style.LightTheme); 
recreate(); 
Verwandte Themen