2012-01-10 9 views
22

Quiero dar al usuario la opción entre algunos temas diferentes, y me preguntaba si esta es una forma correcta de hacer las cosas. Hice una pequeña prueba con este método y funcionó, pero creo que puede haber mejores formas y creo que puede causar algunos problemas más adelante, por lo que quería preguntar.Elección del usuario que implementa el tema

Estaba pensando en crear un diseño diferente para cada tema, y ​​en onCreate acaba de tener un interruptor para el método setContentView(). Cargaría primero un valor SharedPreference guardado (entero) y, dependiendo de qué valor se muestre, se mostrará el diseño correspondiente. Obviamente, el usuario podría cambiar el valor SharedPreference con un botón o algo así.

Como estos diseños serían básicamente los mismos pero con diferentes colores, me gustaría usar los mismos ID para mi TextViews y otras Vistas en cada archivo de diseño. Mi pregunta principal es si esto causaría problemas?

Lo siento por el muro de texto sin código. Me gustaría obtener una idea general de las buenas prácticas para esta situación. Gracias por adelantado.

Respuesta

37

De hecho, tengo esta característica en mi aplicación y, además, les permito a los usuarios cambiar el tema en tiempo de ejecución. Como la lectura de un valor de las preferencias lleva algo de tiempo, obtengo una identificación de tema a través de una función accesible globalmente que contiene el valor en caché.

Como ya se señaló, cree algunos temas de Android, usando this guide. Tendrá al menos dos elementos <style> en su archivo styles.xml. Por ejemplo:

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

Ahora, usted tiene que solicitar uno de estos estilos para sus actividades. Estoy haciendo esto en el método de activida onCreate, antes que cualquier otra llamada:

setTheme(MyApplication.getThemeId()); 

getThemeId es un método que devuelve caché ID Tema:

public static int getThemeId() 
{ 
    return themeId; 
} 

Este campo está siendo actualizado por otro método:

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

que se llama cada vez que se cambian las preferencias (y, al inicio del curso). Estos dos métodos residen en la clase MyApplication, que se extiende en Application. El oyente de cambio de preferencia se describe al final de esta publicación y reside en la clase de actividad principal.

Lo último y bastante importante: el tema se aplica cuando comienza una actividad. Asumiendo, puede cambiar un tema solo en la pantalla de preferencias y que solo hay una manera de llegar allí, es decir, de una sola actividad (principal), esta actividad no se reiniciará cuando salga de la pantalla de preferencias: el tema anterior seguirá siendo usado. Aquí está la solución para que (reinicia su actividad principal):

@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 es una variable booleana, inicialmente establecido en false. Se establece en true cuando el tema se cambia por este oyente, que también actualiza ID tema en caché se mencionó antes:

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

Recuerde que debe mantener una referencia al objeto detector, de lo contrario será basura, recolectados (y dejará de trabajo)

+0

¡Excelente respuesta, muchas gracias! –

+0

Pensé que podría resolver sin extender la Aplicación, pero el problema es que 'getApplicationInfo(). Theme' no se actualiza si hago una' getApplication(). SetTheme (myThemeId) '... así que sí, tu camino es correcto . – vault

+1

Parece que hay un método más simple para reiniciar una actividad actualmente: 'recreate' (https://developer.android.com/reference/android/app/Activity.html#recreate%28%29). – BlueMonkMN

2

Funciona si lo haces de esta manera, y no creo que cause ningún problema, pero parece una gran molestia (tienes que multiplicar todos tus diseños por todos los temas que quieras agregar Si luego desea modificar un recurso en un diseño, tendrá que modificarlo en todos los temas. Definitivamente debe olvidar uno)

¿Por qué no utilizar la característica Styles and Themes de Android?

Pueden ser aplicados a toda la actividad fácilmente:

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

Así que cuando se detecta un cambio en el valor SharedPreferences usted (botón en una actividad de preferencia, o algo así) el uso que usted puede simplemente cambiar el estilo . O mejor, puede configurar el estilo para leer su valor de preferencia en el tiempo de ejecución (al crear la actividad) y aplicar el estilo/tema correcto en consecuencia.

+0

Voy a leer la función Estilos y temas e intentar hacerlo de esa manera, gracias por la información. Te votaré en una hora porque los utilicé todos ayer: P –

2

También puede cambiar dinámicamente el tema usando:

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

Antes onCreate para cada actividad.

Cuestiones relacionadas