Establecer dinámicamente el color del tema

Estoy utilizando temas (dinámicamente) en mi aplicación para Android, así:

My_layout.xml (extracto):

<TextView android:id="@+id/myItem" style="?my_item_style" /> 

Attrs.xml (extracto):

 <attr name="my_item_style" format="reference" /> 

Themes.xml (extracto):

 <style name="MainTheme.Blue"> <item name="my_item_style">@style/my_item_style_blue</item> </style> <style name="MainTheme.Green"> <item name="my_item_style">@style/my_item_style_green<item> </style> 

Styles.xml (extracto):

 <style name="my_item_style_blue"> <item name="android:textColor">@color/my_blue</item> </style> <style name="my_item_style_green"> <item name="android:textColor">@color/my_blue</item> </style> 

Por lo tanto, como puede ver, estoy estableciendo temas dinámicamente. Estoy usando esta clase:

 public class ThemeUtils { private static int sTheme; public final static int THEME_BLUE = 1; public final static int THEME_GREEN = 2; public static void changeToTheme(MainActivity activity, int theme) { sTheme = theme; activity.startActivity(new Intent(activity, MyActivity.class)); } public static void onActivityCreateSetTheme(Activity activity) { switch (sTheme) { default: case THEME_DEFAULT: case THEME_BLUE: activity.setTheme(R.style.MainTheme_Blue); break; case THEME_GREEN: activity.setTheme(R.style.MainTheme_Green); break; } } 

}

¿Qué quiero saber, hay una manera de cómo hacer esto (cambiar el color del tema) en el código? Por ejemplo, tengo el siguiente código (extracto):

 ((TextView) findViewById(R.id.myItem)).setTextColor(R.color.blue); 

Se puede hacer por algún método auxiliar, que utilizaría el comando switch para los temas disponibles y devolverá el color correcto para un tema. Pero me gustaría saber si hay alguna manera mejor, más agradable y más rápida.

¡Gracias!

Si entiendo corectly usted está buscando una manera de

  1. Extraer un estilo de un tema,
  2. Extraer un valor (color de texto) de dicho estilo.

Hagámoslo.

 // Extract ?my_item_style from a context/activity. final TypedArray a = context.obtainStyledAttributes(new int[] { R.attr.my_item_style }); @StyleRes final int styleResId = a.getResourceId(0, 0); a.recycle(); // Extract values from ?my_item_style. final TypedArray b = context.obtainStyledAttributes(styleResId, new int[] { android.R.attr.textColor }); final ColorStateList textColors = b.getColorStateList(0); b.recycle(); // Apply extracted values. if (textColors != null) { textView.setTextColor(textColors); } 

Un par de notas:

  1. TypedArray no admite la obtención de elementos vectoriales de soporte y referencias de temas en listas de estado de color en niveles de API más antiguos. Si está dispuesto a utilizar AppCompat API interna, puede intentar TintTypedArray .
  2. Asignar int[] todo el tiempo es costoso, lo convierten en un static final .
  3. Si desea resolver varios atributos a la vez, la matriz de atributos debe ser ordenada. De lo contrario se bloquea a veces. <declare-styleable> genera tal matriz e índices correspondientes para usted.

Finalmente lo he hecho usando el siguiente método:

 public static int getColor(String colorName) { Context ctx = getContext(); switch (sTheme) { default: case THEME_DEFAULT: return ctx.getResources().getIdentifier("BLUE_" + colorName, "color", ctx.getPackageName()); case THEME_BLUE: return ctx.getResources().getIdentifier("BLUE_" + colorName, "color", ctx.getPackageName()); case THEME_GREEN: return ctx.getResources().getIdentifier("GREEN_" + colorName, "color", ctx.getPackageName()); } } 

Esto devuelve el color según mi tema (usé prefijos).

¿Has comprobado esta demostración de MultipleThemeMaterialDesign ?

Introduzca aquí la descripción de la imagen

SettingActivity:

 @Override protected void onCreate(Bundle savedInstanceState) { Preferences.applyTheme(this); getDelegate().installViewFactory(); getDelegate().onCreate(savedInstanceState); super.onCreate(savedInstanceState); setToolbar(); addPreferencesFromResource(R.xml.preferences); Preferences.sync(getPreferenceManager()); mListener = new SharedPreferences.OnSharedPreferenceChangeListener() { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { Preferences.sync(getPreferenceManager(), key); if (key.equals(getString(R.string.pref_theme))) { finish(); final Intent intent = IntentCompat.makeMainActivity(new ComponentName( SettingsActivity.this, MainActivity.class)); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | IntentCompat.FLAG_ACTIVITY_CLEAR_TASK); startActivity(intent); } } }; } 

Ver ejemplo completo de demostración.

¿Qué pasa con la identificación del tema a través de Intent ?

 Intent intent = new Intent(activity, MyActivity.class); intent.putExtra("theme", R.style.MainTheme_Green); activity.startActivity(intent); 

Y luego en onCreate :

 // assuming that MainTheme_Blue is default theme setTheme(getIntent().getIntExtra("theme", R.style.MainTheme_Blue)); 

Dado el hecho de que cada recurso es un campo dentro de la clase R, puedes buscarlos usando la reflexión. Eso es costoso, pero puesto que usted va a conseguir un valor int, usted puede almacenarlos después de que usted los consiga y evitar la caída del funcionamiento. Y puesto que los métodos que utilizan recursos toman cualquier int, usted puede utilizar una variable del int como placeholder, y después poner el color deseado en él.

Para obtener cualquier recurso:

 String awesomeColor = "blue"; int color = getResourceId(R.color, awesomeColor, false); if(blue>0) ((TextView) findViewById(R.id.myItem)).setTextColor(color); 

La función:

 public static int getResourceId(Class rClass, String resourceText, boolean showExceptions){ String key = rClass.getName()+"-"+resourceText; if(FailedResourceMap.containsKey(key)) return 0; if(ResourceMap.containsKey(key)) return ResourceMap.get(rClass.getName()+"-"+resourceText); try { String originalText = resourceText; if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.GINGERBREAD){ resourceText = ValidationFunctions.normalizeText(resourceText); } resourceText = resourceText.replace("?", "").replace(" ", " ").replace(" ", "_").replace("(", "").replace(")", ""); int resource = rClass.getDeclaredField(resourceText).getInt(null); ResourceMap.put(rClass.getName()+"-"+originalText, resource); return resource; } catch (IllegalAccessException | NullPointerException e) { FailedResourceMap.put(key, 0); if(showExceptions) e.printStackTrace(); } catch (NoSuchFieldException e) { FailedResourceMap.put(key, 0); if(showExceptions) e.printStackTrace(); } return 0; } 

Versión de trabajo aquí: https://github.com/fcopardo/AndroidFunctions/blob/master/src/main/java/com/grizzly/functions/TextFunctions.java

Este tratamiento es válido para cualquier recurso de Android. También puede configurar el tema de esta manera en lugar de utilizar variables intermedias:

 public static void onActivityCreateSetTheme(Activity activity) { int theme = getResourceId(R.style, activity.getClass().getSimpleName(), false); if(theme > 0) activity.setTheme(theme); } 
  • El ajuste textColor de un tema falla sólo en HTC Desire HD
  • Estilo de la casilla de verificación de Android
  • Utilizar atributos en el selector - Android
  • AppCompat ActionBar tema giratorio desplegable
  • Lollipop estilo EditBox
  • Temas aparentemente ignorados en ICS
  • Cómo cambiar el estilo de pestaña en Android?
  • Uso del adaptador ListView personalizado con los temas predeterminados de Android
  • PhoneGap 3.x Android - Tema de Popup / Dialog nativo
  • Cómo establecer un tema diferente en un diseño
  • Theme.Translucent falla en ICS
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.