How to apply a custom theme to an Android application
July 20, 2012 | 4 min ReadSince the release of Android 4.0, we have seen an increase in applications that follow the new Android design guidelines. The guide describes the Android holo theme that provides a cohesive user experience that is both modern and unique. At this years Google IO talk “Android Design for Success”, we got a handy outline of how important these guidelines can be:
Hierarchy of Needs (courtesy of the folks at Google)
For this post, I’ll assume you have the ground covered in the “Successful design” segment. So let’s head out into app nirvana. More specifically I’ll describe some useful patterns when applying heavier branding to your application.
Simple styles
The simplest way to declare the visual appearance in Android is to set properties directly on the View object. Since this isn’t very convenient when styling an entire application, we can create styles that bundle properties of view. A style can than be set onto a view. But be aware that a style can only be set in xml. That means that we can only set a style once because the style properties are evaluated when the View is created/inflated. Here is an example of how to set properties for a TextView in the res/values/styles.xml file.
<item name="android:textSize">20sp</item> <item name="android:textColor">#008</item>
To reference this style in our layout.xml files we use @style/CustomText
. The style declaration references a parent style called @android:style/TextAppearance.Medium
. Since the style reference begins with android:
namespace, we know that it is one of the default styles shipped with the Android platform.
Creating themes to bundle styles
Let’s assume we want to change the text size and color on all of our TextViews and don’t want to set it explicitly on every TextView. This is a very common scenario and luckily Android offers a pretty powerful mechanism via themes. In essence, a theme is a style resource itself that uses “keys” to point to concrete styles. A View object greps the concrete style to apply based on the key. Here is a simple example that would be declared in the res/values/themes.xml
file:
<item name="android:textAppearance">@style/CustomText</item>
As mentioned above, a theme is style resource itself so we declare a Theme.App
that inherits from the dark holo theme provided by the Android platform. We also assign our CustomText style to the attribute android:textAppearance
. An attribute is a predefined “variable” that can hold references to other resource elements. In fact, it is also possible to create custom attributes in the res/values/attr.xml
file.
Now, here comes the interesting part. Our theme Theme.MyApp
can not only be applied by setting it on an Activity in the AndroidManifest.xml
, it can also be set during runtime in code. You would have to restart the current Activity (or use a ContextWrapper
to theme parts of your UI) but it makes theming much more dynamic.
How to find out what attributes to set on widgets
The most common problem with theming is to find out what attributes apply to which View. The only reliable way to find all the corner cases is to have a look at the source code of the View we want to theme. The following snippet shows parts of the TextView class in Android api level 16 (Jelly Bean). The snippet is executed in the constructor (code passages are omitted).
final Resources.Theme theme = context.getTheme();
TypedArray a = theme.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TextViewAppearance, defStyle, 0);
int ap = a.getResourceId(com.android.internal.R.styleable.TextViewAppearance_textAppearance, -1);
TypedArray appearance = theme.obtainStyledAttributes(ap, com.android.internal.R.styleable.TextAppearance);
textColor = appearance.getColorStateList(attr);
The snippet shows how the text color is extracted from the current theme using the attribute TextAppearance
. By reading through this initialization code we can usually derive what kinds of elements can be configured.
We have to be aware though, that different Android versions apply different attributes. While higher Android versions usually support older attributes, newer attributes are obviously not interpreted by older Android versions. I hope we will get a Lint check soon when referencing theme attributes that are introduced on newer Android versions.
Wrap up
Theming has gotten much more powerful with Android 4.0. Ninety-eight percent of the attributes that can be set via code, can now be set via styles and are therefore themeable. In addition to the greater visual flexibility when using a custom theme, you also reduce clutter in your xml layouts and in your java code which can now be completely devoted to the app’s logic.