Tuesday, June 30, 2009

Custom adapter in color

I got a comment on this blog with relation to an old sin of mine, the custom adapter example program. That example was about custom views in a list adapter. The comment was innocent enough: is there a way to change the colors of that list? I thought it was a 5 minute task to answer that question, in the end I had to deal with a topic I never wanted to know about: themes.

Click here to download the example program.

It turned out that the color scheme used by ListView is eventually taken from the active theme. It is possible to change it programmatically but it is quite complicated to do so. Meanwhile, with themes, it is relatively easy. If you know the information source. The Android development guide is almost completely useless regarding themes, for example sample themes don't work. This blog entry from Brainflush is much more informative, at least its examples work. The source that helped me the most was the actual Android XML fileset that defines the themes. If you have access to the Android source tree, the Android system resources can be found under the platform\frameworks\base\core\res\res directory. The relevant files are styles.xml under the values subdirectory and the content of the drawable subdirectory.

If you check the styles.xml in the res/values directory in our example program, you will see that modifying the color scheme of the ListView is a quite complicated, multi-step process. First of all, in res/values/styles.xml, the ListView style is overridden with the android:listViewStyle property. The ListViewStyle (MyListView) in turn references a list selector (android:listSelector) that is stored in the res/drawable directory. That selector defines color schemes for all the possible state combination of the list row. To increase the fun, the resource compiler screwed up the image IDs in the R.java file if the weather icon image files were not at the beginning of the file name list, hence the bizarre names in the drawable subdirectory. Now what we need more is a transition that refers a 9-patch background image (block blue in our case) for the selected row and we are ready.

Don't say that it was not easy.

PS: I apologize for the hideous colors. :-)


Marcus said...

Thanks for the post. I will have a look into the example soon.

I also digged very deep into the themes story and made the same experiences (dev guide is useless).

My problem: I want to use the system light theme. The problem are listviews in alertdialogs! They get a white background and also a white textcolor, so not readable.

It took me nearly one day to find a workaround. There are also some questions about that in the google dev groups. But no clear solution.

Do you have an answer to that?

(just create an activity with light-theme, then create and show an alertdialog with an adapter set...)

Gabor Paller said...

Hi, Marcus,

As I proposed in the post, I think you should check the system style and themes files. These are themes.xml and styles.xml. I checked themes.xml and I noticed that alertDialogStyle is not set for Theme.Light. I don't know what the default is but clearly, it is not in sync with Widget.ListView.White style which is set as listViewStyle for Theme.Light.

I propose that you set the style explicitly for your alertDialog and define that style in your own styles.xml file.

Marcus said...

Hi, thank you for reply.

Sadly it isn't as easy as it seems... ;)

I checked the system themes and styles. But also if I derive a Theme from Theme.Light and set the alertDialogStyle, it doesn't work. Looking into the reference shows that this attribute only affects the drawables, not the styles used for a listview inside an AlertDialog.

I create the AlertDialog via the AlertDialog.Builder for convenience (you can set directly an adapter without having an own layout). And I also checked the source of AlertDialog & Builder... it is using the default Theme.Dialog style. And sadly the builder has no possibility to set an own style! :(

If you like just try it as I described in my previous comment (last sentence).

Gabor Paller said...

The text appearance style has to be set on the individual elements of the child view of ListView.

I updated the example program (download again if you have already downloaded it). The display became even more ugly. :-)

What it demonstrates, however, how to set the text style of list elements (including color). Check out the SpecialText style in res/values/styles.txt and see, how that style is applied in WeatherAdapter.java.

yuantech said...

Thanks for the info and the example codes. My question is how should i override the baseAdapter class so that I could use multiple choice type of list?

Hope for your reply soon. :)

Gabor Paller said...

"so that I could use multiple choice type of list? "

That's not the adapter's problem. Use android:choiceMode="multipleChoice" in the layout file. Documentation at the android.widget.ListView class.

Radu Motisan said...

Another custom adapter listview example:

without using XML resources.

ryan foster said...

AlertDialog.Builder is hardcoded to use com.android.internal.R.style.Theme_Dialog_Alert.

So you'd have to rewrite the Dialog