Dynamic themes and custom styles

I have an application with two themes (dark and light) that can be selected at runtime. It works. I also have a ListView with strings that can have one of three different layouts, each of which has a style (say, different colors). This also works. But I can not get these two functions to work together. I really need six different styles, three for one topic (dark) and three for another (light), but I can’t figure out how to choose a style for a list item based on the current topic or get this effect in another way using XML files. My three layouts each point to a custom theme that sets the color, but that overrides any theme I installed. Themes can only contain elements that are β€œcustom”, so I cannot post my own custom elements. There may be a way to do this programmatically, but I was hoping to do it declaratively. Any ideas?

+4
source share
2 answers

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 :

 <!-- Attributes we use to set the text color of the various list items. --> <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:

 <!-- Mix-in style for activities. --> <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.

+7
source

Once upon a time, Lawrence Kestelout published his decision in 2012. Now six years later, the new Android in Android has tried to solve a similar problem:

How can I exchange the whole style of the application by simply exchanging one theme?

This is a generalization of Lawrence's question on how to organize two interchangeable topics.

I figured out a solution based on Lawrence, and take a step further.

(Not claiming that this is an ideal solution, but an improvement).

Lawrence found out the power of user-defined attributes to achieve this. He uses them to address colors depending on the chosen topic.

While this works, you still need to define attributes for each property. It does not scale well. So why not associate properties with styles and themes and use the same mechanism?

The result is a main theme that defines child themes and styles.

RES / value / attrs.xml

 <resources> ... <attr name="mainViewTheme" format="string"/> <attr name="asideViewTheme" format="string"/> ... </resources> 

When defining an attribute for setting a theme, there is no special format for it. The format string does this.

RES / value / styles.xml

 <style name="MasterTheme"> ... <item name="mainViewTheme">@style/MainViewTheme</item> <item name="asideViewTheme">@style/AsideViewTheme</item> ... </style> <style name="MainTextTheme"> ... </style> <style name="MainViewTheme"> ... </style> 

Res / layouts / main.xml

 <TextView android:theme="?mainViewTheme" ... 

By exchanging the main theme, all styles are customizable. It still requires defining several attributes of the theme, and then does a powerful job. Setting attributes for each property is no longer required.

+1
source

Source: https://habr.com/ru/post/1442674/


All Articles