Understanding Android Themes and Styles
I don’t know how many hours I’ve spent struggling with Android’s theme engine, trying to figure out — mostly by trial and error — how styles are applied and how to properly define them (let’s be honest: the documentation on styles in Android is a bit lacking). I thought it may be worth sharing what I’ve found out so far, in order to save my fellow Android developers from baldness due to ripped out hair (I sure lost some). This is a work in progress (so is Android), and some information may be inaccurate. If you find anything that you think is wrong or unclear, please let me know by dropping a line in the comments section. On another note, I assume that you have read the reference documentation on Android styles, if not, you should do that now.
What are Android styles?
A style in Android is a collection of attribute/value pairs applied to a view, an Activity or the entire application (which means, all Activities in your application). Styles for Activities are called themes, but do not get confused: they are syntactically equivalent to styles (because they are styles), they merely have a different scope. At this point I want to clarify something upfront: Themes or styles in Android have nothing to do with user styles known from applications such as, say, Firefox. Android users can not change the looks of Android applications by downloading themes from the Market or creating their own (yet). Android themes are of interest for developers only, think of them as syntactic sugar, a way of making your application’s view code more DRY.
How do I define custom styles?
Let’s look into a simple theme definition (stored in res/values/styles.xml):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MyTheme" parent="android:Theme.Light">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@color/translucent_blue</item>
<item name="android:listViewStyle">@style/MyListView</item>
</style>
<style name="MyListView" parent="@android:style/Widget.ListView">
<item name="android:listSelector">@drawable/list_selector</item>
</style>
</resources>
First, we declare a new theme called MyTheme, which inherits from another theme called Theme.Light in the android namespace (specified by the ‘parent’ attribute). This means that all styles we do not explicitly specify in our custom theme will be merged down from the definition of android:Theme.Light (the curious among you may want to download the Android source code and go to frameworks/base/core/res/res/values to see how it is defined; all stock styles are defined in themes.xml and styles.xml in that folder).
In our theme definition, we also set some custom styles using the ‘item’ element. We set the windowNoTitle attribute to true, so all activities that use our theme won’t have a title bar. We also set the window background color to a custom color called ‘translucent_blue’; this is a resource reference (indicated by the @ symbol) to a color definition in values/colors.xml. We could also have passed a reference to a drawable here, or have provided a hex color value directly. Finally, we set the default style for ListView widgets to a custom style called MyListView. Its style definition follows the exact same structure as the MyTheme definition, just that this time it is not a theme, but simply a style that can be applied to ListView objects. It inherits from the default styles for ListView but replaces the default selector image with a custom drawable.
There are two important things to understand here. First, those two style definitions are completely independent of each other (well, apart from the fact that we reference MyListView in MyTheme of course). This means, that if I remove the reference to MyListView from MyTheme, I can still use that style by applying it manually to a ListView declaration in a layout file. Think of styles simply as a bunch of attributes and values you would have otherwise typed directly into your view definition, so instead of writing
<ListView android:listSelector="@drawable/list_selector" />
we write
<ListView style="@style/MyListView" />
or better yet, we let this style be applied automatically to all ListView widgets by setting it in a theme definition (as seen above). (Note the missing ‘android:’ namespace reference here; this is intentional, the ’style’ attribute is not defined in the ‘android’ namespace. You will get an error if you try to set a style using ‘android:style’, there is no such attribute.)
That way we never have to touch the ListView definition anymore; we can do all its styling from a single point, the style sheet. This helps in leaving the code for defining structure in your layouts, while leaving the code for defining appearance in your style sheets — a good example for separation of concerns. More importantly, your style definitions can be reused, which is particularly useful if styles are shared between several views.
The other important thing to understand is that styles do not have any type semantics. When we create a style called MyListView which inherits from Widget.ListView, then the intuition is that we are creating a style that is only supposed to apply to ListView objects. That’s not entirely correct though. There is no mechanism that will check whether we indeed apply that style to a ListView or even prevent us from applying it to an entirely different view type. It just so happens that Widget.ListView defines some attributes that only make sense when being applied to a ListView (such as listDivider), this doesn’t stop us, however, from creating a style that totally makes sense for any widget type (maybe because it only uses attributes defined in the View class, the parent class of all views). The bottom line is that you have to figure out yourself whether a style you define makes sense when you apply it to a view. Android will not do any sanity checks for you. In the worst case, the targeted view will expose odd behavior when being rendered, but more probably nothing will happen at all.
So what can I style, and from what can I inherit?
To get going with styles, it’s of course important to know two things:
- what’s there to be styled, and
- what styles are already there to inherit from
The easy answer is: Anything in android.R.styleable can be used inside a style body as a subject for styling (using the item tag), while anything in android.R.style can be used as parent styles to inherit from. So, to stick with the ListView example style, the android:listSelector style item can be found in android.R.styleable, while android:style/Widget.ListView is defined in android.R.style. Those two files are therefore what you want to turn your attention to first when defining custom styles. You should generally always inherit all default style items first, and then overwrite them one by one with your custom items.
That’s basically already it, a simple yet powerful style framework if used correctly!
Useful Tidbits
Text Appearance
Did you find yourself defining text appearance like font size or text color over and over again in your layouts? Don’t do that, use text appearances instead. Text appearances are styles, too, and Android already defines some for you which you can override (they are, of course, defined in R.style). This helps tremendously in keeping your view code DRY, and encourages you to get some structure into your different font styles used throughout your app by grouping them into styles you can reference and reuse. If, for example, you want to change the default text appearance in your app, simply define a custom text appearance in your stylesheet and set it as the default in your theme:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MyTheme" parent="android:Theme.Light">
<item name="android:textAppearance">@style/MyDefaultTextAppearance</item>
</style>
<style name="MyDefaultTextAppearance" parent="@android:style/TextAppearance">
<item name="android:textSize">12sp</item>
<item name="android:textColor">#333</item>
<item name="android:textStyle">bold</item>
</style>
</resources>
Make yourself familiar with all the text appearances Android already defines, and customize them for your application as you see fit.
Colors
Avoid setting color values directly in layouts or styles. Define them in a color resource file instead, and only use references to those color values from your layouts and styles. This helps in isolating them from the rest of your view code and makes your styles less brittle if you should decide to change a color afterwards. For simple, non-stateful colors, you can simply create a colors.xml file in res/values:
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<color name="default_text_color">#FFEAEAEA</color>
...
</resources>
Often, however, colors can be more complex. If, for instance, you use a custom list selector image, it may happen that list text is readable when not selected, but becomes difficult or impossible to read when the custom selector is drawn (e.g. because the coloring is too similar). In that case, you need a ColorStateList, which you can use to automatically change colors for the view it’s applied to, based on that view’s state. Start by creating a new file, e.g. ’stateful_text_color.xml’ in your res/colors directory. The resource root is ’selector’, which is what you always use when creating resources that change with a view’s state:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:color="#333" /> <item android:state_window_focused="false" android:color="#CCC" /> <item android:state_pressed="true" android:color="#FFF" /> <item android:state_selected="true" android:color="#FFF" /> <item android:color="@color/default_text_color" /> <!-- not selected --> </selector>
You get the idea. You can set this stateful color resource like any other color, it’s simply defined in a different way.
Also keep in mind that there are already color definitions shipped with Android. The most useful of them is probably android:color/transparent, which corresponds to the color #00000000. The first 8 bit, i.e. the first two hex digits, represent the alpha channel which is used to define opacity. A value of zero means zero opacity, or 100% transparency; the remaining color bits are therefore of no relevance, because they will be invisible. You can then turn the background of your views transparent by doing something like:
<style name="MyListView" parent="@android:style/Widget.ListView"> <item name="android:background">@android:color/transparent</item> </style>
That’s it for now. If I find out more about styles in Android, I’ll update this post accordingly. Feel free to contribute in the comments section, too.
Wow great info. I’ve bookmarked your site.
thanks! This topic really helped me understand styles and themes in its basic form :)
Android’s SDK documentation is really giving me a tough time… geez
Great stuff. Thanks for the tips!
It’s giving an error like – “No resource found that matches the given name (at “android:windowBackground” with value ‘@color/translucent_blue’
hi,Jarvarm
You asked the below question previously, i also get the same problem.so,if you get any solution to this please forward to jettimadhu@gmail.com.
It’s giving an error like – “No resource found that matches the given name (at “android:windowBackground” with value ‘@color/translucent_blue’
Thanx in advance
that was just an example, there is no predefined color called “translucent_blue”.
You have to create a file res/colors.xml and define all colors you use in that file. Or use the ones coming with android (@android:color/some_color).
ok..jusst figured out. Need to define colors.xml
Great tutorial. Thanks.
Thanks a lot, you saved me from balding a little more :)
Kudos. Wish the android docs were this clear.
I’m specifically try to create a dialog with a icon in the title bar (the menu more icon). I can use @Theme.Dialog to get almost all the way there, but not the icon. Is the icon something styleable, or do I need to go in muck about with new low level view definitions?
Hey Charles,
glad to hear that. As to your problem, I don’t believe title bar icons are set using styles; title bar features are typically changed by going through the Window class. Did you already try something like this:
dialog.requestWindowFeature(Window.FEATURE_RIGHT_ICON);
dialog.setFeatureDrawable(Window.FEATURE_RIGHT_ICON, iconDrawable);
I didn’t actually test this code, but I believe it’s going in the right direction. Also, remember that custom window features must be requested before adding any content to the dialog (same for activities). Check the Dialog and Window class documentation for more info.
Cheers,
Matthias
[...] 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 [...]
[...] Taken from brainflush blog [...]
[...] project. started searching for other tutorials on the net on Android, like the one found on this link. There are tutorials found on the Android site but I’ve been trying to understand them for a [...]
Hi Matthias Käppler,
Thanx for your reply.Is there any alternative without help of colors.xml
Thanks for writing this great post. All that information should go into the official Android documentation.
(Oh dear, formatting did not work on the previous one. Please delete)
Very useful post. I’ve bookmarked it too.
One question: suppose I want to style something from a different namespace? I.e. I’ve defined my own widget class with its own attributes. In the layout.xml file, I would do:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:gridbox="http://schemas.android.com/apk/res/org.efalk.gridtest" >And everything would work fine. But in styles.xml
<style name="bigButton"> <item name="android:gravity">center</item> <item name="gridbox:layout_colspan">2</item> </style>I get “ERROR: No resource found that matches the given name: attr ‘gridbox:layout_colspan’”
Any ideas how I can use styles with additional namespace?
The difference is that xmlns:mynamespace=”…” is simply an instruction to your XML parser that whenever the prefix ‘gridbox’ is encountered, it should be expanded to “http://schemas.android.com/apk/res/org.efalk.gridtest”. That’s an XML thing, not an Android thing, and it’s really just to make an XML file easier to read and write. There is nothing checked about this, the URL and prefix could be anything that’s allowed in an XML file.
Not so with the second example. You can only reference attributes in a style definition which are declared somewhere (i.e., they must be accessible through the R class). What you must do is create an attrs.xml in your res/values folder, and do something like:
<?xml version="1.0" encoding="utf-8"?> <resources>> <declare-styleable name="YourWidget"> <attr name="layout_colspan" format="integer" /> ... </declare-styleable> </resources>Android will then use your schema URL (which you probably have noticed contains the package name of your app) and tries to find that styleable in your package’s R class. However, that only works in the scope of a single application. You cannot use stylables from other applications (just in case you’re trying to create a shared lib, I tried, and failed miserably :-)
There’s a blog article about declare-styleable here:
http://blog.pocketjourney.com/2008/05/02/android-tutorial-42-passing-custom-variables-via-xml-resource-files/
oh and, in the constructor of your custom widget that takes an AttributeSet as the second argument (that’s the ctor that will be called when the view is being inflated from XML), you have to call obtainStyledAttribute() to do something with layout_colspan.
I need someone to style my android apps. Anyone interested?
Matthias, you can simply use @android:color/transparent (which also works as a drawable btw) instead of defining your own transparent color. Also, colors can be defined as color lists and contains different colors values for different states. The content or res/color/ in the framework source code shows several example of this. This is how we change the color of items in lists when they are selected for instance.
Hi Romain, yes, actually I’m aware of android:color/transparent. I never got to update the post (it’s like half a year old). We also use color lists in our application now, which is very useful when elements like text need to change color depending on their state (selected, pressed, etc.)
Thanks for the reminder though!
I’ve updated the section about colors to include your feedback. Thanks again.
Actually I was just looking for info like this yesterday, and today I found this excellent bit. Thanks for sharing!!