Thanks wingman for a clue . My situation is with colors, which are a little more complicated, so I will write my solution here.
I have two themes (light and dark) that the user can select on the settings screen. I have a ListView that can have two types of strings (simple and prominent), each with its own style. First, each layout should point to a style:
<TextView style="@style/PlainItemText" ... />
(or NoteItemText ), and we need to define the styles:
<style name="PlainItemText"> <item name="android:textSize">@dimen/list_item_font_size</item> <item name="android:textStyle">bold</item> <item name="android:textColor">?plainTextColor</item> </style>
The color of the text cannot be corrected, because it depends on the chosen theme. We must create a custom attribute and refer to it with a question mark, as indicated above. We define the attribute in res/values/attrs.xml :
<attr name="plainTextColor" format="reference|color"/> <attr name="noteTextColor" format="reference|color"/>
Then we can define different colors. Here we have two styles and two themes, so we need four lists of color states, each in its own file under res/color . For example, here res/color/plain_text_color_dark.xml :
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_window_focused="false" android:color="@android:color/white"/> <item android:state_selected="true" android:color="@android:color/black"/> <item android:state_focused="true" android:color="@android:color/black"/> <item android:state_pressed="true" android:color="@android:color/black"/> <item android:color="@android:color/white"/> </selector>
The selected / focused / pressed colors are the same in all these files because they exceed the color of the backlight. Be careful with the state_window_focused version. It did not behave as advertised, and I had to set it by default (last line above) in all cases. Now we need to create our themes and bind attributes to one of the colors. These lines go to res/values/themes.xml :
<style name="Theme.Dark" parent="android:Theme"> <item name="plainTextColor">@color/plain_text_color_dark</item> <item name="noteTextColor">@color/note_text_color_dark</item> </style> <style name="Theme.Light" parent="android:Theme.Light"> <item name="plainTextColor">@color/plain_text_color_light</item> <item name="noteTextColor">@color/note_text_color_light</item> </style>
Finally, we select the runtime theme in the Activity onCreate() method before calling super.onCreate() :
if (isDarkTheme) { activity.setTheme(R.style.Theme_Dark); } else { activity.setTheme(R.style.Theme_Light); }
Please note that I do not take into account newer topics such as Holo, so my application looks old on Honeycomb and later. I will fix it at some point, but it was not a regression here.
The twist in my case is that some actions have a large title bar to fit some buttons. Basically, I had to create four themes, light and dark for a narrow name, as well as light and dark for a bold name. But instead, I created a mixed style:
<style name="ButtonTitleBar"> <item name="android:windowTitleSize">44dp</item> </style>
and procedurally add it to any topic I use. This code starts right after setTheme() calls:
if (buttonTitleBar) { // Mix in this other style. Resources.Theme theme = activity.getTheme(); theme.applyStyle(R.style.ButtonTitleBar, true); }
I have not seen this documented anywhere, and I do not know if it is legal, but the code of Activity.getTheme() implies that it should work fine, and it worked in all my tests. This will help to avoid a combinatorial explosion of those that you can find in the standard list of themes for Android.