How to avoid headaches with Android themes and styles

Android is really a beautiful platform to develop on. It has a well-thought framework (Activites, Intents…), smart concepts (Java-XML relation, scalable 9-patches…), precise documentation and helpful tools to make designing your own app become a real pleasure. It’s quite easy to learn, and soon after your HelloWorldApp you realise that you have the power to design really cool apps. That’s when you become aware that a cool app design highlights cool functionality and therefore brings loads of cool users.

Luigi

Luigi, the artist in you

But if you go deep into the design and branding process, you’ll reach areas that, to quote the Android doc itself, are “not well documented”: styles and themes. Indeed,

“The R.style reference, however, is not well documented and does not thoroughly describe the styles, so viewing the actual source code for these styles and themes will give you a better understanding of what style properties each one provides.”

(http://developer.android.com/guide/topics/ui/themes.html#PlatformStyles)

Together with the concepts of styles and themes, you’ll find things like theme attributes (R.attr), styleable properties (R.styleable), text appearance, theme inheritance, etc. And those can really give you a massive headache if you don’t have clearly in mind the subtleties of each. I recently tried to design custom AlertDialogs from Holo models, and eventually came through all of those concepts, realising that it’s not straightforward at all. I’ll try to clarify things from the beginning.

All the informations presented in this article are a summary of:

This article is addressed to beginning as well as advanced Android developers. You’ve already dealt with Android XML files (resources, layouts, values…) and you’re trying to understand what is R.attr and what is a textAppearance? Or you’re thorough when it comes to branding and you want to know the best and easiest way to customise your app with your own themes while meeting the standards? Then this article is for you.

What are themes and styles in Android?

Overview

Let’s start with a basic comparison of Theme and Style.

 ThemesStyles
DefinitionIn a resource file, usually themes.xml
<style> tag with a name prefixed by Theme.
In a resource file, usually styles.xml
<style> tag
UsageIn the Android Manifest
<application android:theme="@style/Theme.LE_THEME"> for an application-global theme
or
<activity android:theme="@style/Theme.LE_THEME"> for an activity-specific theme
In any layout file
<AnyWidget style="@style/LE_STYLE">

AnyWidget being Button, TextView, LinearLayout, ScrollView, etc.
Android defaults
(API level 19)
General themes
Theme
Theme.Black
Theme.Light
Theme.DeviceDefault
Theme.DeviceDefault.Light
Theme.Holo
Theme.Holo.Light


Sub-themes
Theme.NoTitleBar
...
Theme.Black.NoTitleBar
...
Theme.Light.NoTitleBar
...
Theme.DeviceDefault.NoActionBar
...
Theme.DeviceDefault.Light.NoActionBar
...
Theme.Holo.NoActionBar
...
Theme.Holo.Light.NoActionBar
Theme-related widget styles
Widget.Button
Widget.Button.Small
...
Widget.DeviceDefault.Button
Widget.DeviceDefault.Button.Small
...
Widget.DeviceDefault.Light.Button
Widget.DeviceDefault.Light.Button.Small
...
Widget.Holo.Button
Widget.Holo.Button.Small
...
Widget.Holo.Light.Button
Widget.Holo.Light.Button.Small
...


Theme-related property styles
TextAppearance.Small
TextAppearance.Small.Inverse
...
TextAppearance.DeviceDefault.Small
TextAppearance.DeviceDefault.Small.Inverse
...
TextAppearance.Holo.Small
TextAppearance.Holo.Small.Inverse
...


Standalone styles
MediaButton
MediaButton.Play
MediaButton.Next
...
The main points we get from this table are:

  • A theme is in fact a style, the only difference is where each is used: you set a theme in the Manifest on the app or an activity, whereas you set a style in a layout file on a widget.
  • There are more styles than themes (styles.xml is bigger than themes.xml). That’s because the definition of a theme is in essence a collection of references to the styles that the theme will use. That means that Theme.Holo will reference and use
    • Widget.Holo.Button
    • Widget.Holo.Button.Small
    • TextAppearance.Holo.Small
    • TextAppearance.Holo.Small.Inverse

    We’ll see later how a style is actually referenced in a theme.

  • Themes can be divided in general themes and sub-themes. For instance, when you’re designing a theme for your app, you’ll work on Theme.LE_THEME. But you can imagine that somewhere in your app you need a special activity that won’t show an ActionBar. You should then create a sub-theme Theme.LE_THEME.NoActionBar for this activity. Your Android Manifest will look like:

  • All your activities, including MainActivity, will use the theme defined at the application level, except those that override the application theme, like SpecialActivity.
  • Styles can be divided into 3 categories:
    • Theme-related widget styles: these are styles whose name explicitly indicates what widget it defines. When you read the Widget.Holo.Light.Button.Small style definition, you know it refers to small buttons in the light version of Holo theme.
    • Theme-related property styles: they define properties that are not bound to one widget only. For example, TextAppearance.Small defines the size and the color of a small text. But this appearance is not specific to a widget as a small text can be displayed in a small button, or in a small ActionBar tab, or whatever…
      We’ll see later how a widget references the text appearance it used.
    • Standalone styles: these are less common, they are styles that are valid whatever the theme used. In the table above, MediaButton, you can imagine that a MediaButton will always look the same across all themes.

Inheritance

One of the interesting properties of the styles/themes is that you can inherit an existing style/theme, but the way to do it can be quite subtle.

Solution #1: with explicit parent attribute

This is the most common way to do it and the way you may have learn. If you want to define a style Child that inherits all the properties from another style Parent you just write:

Then in Child you can define properties that override Parent properties, and/or add new properties. And you can of course inherit Android default styles/themes as well as your own. For example, to define your application’s new main theme you could do:

Solution #2: with implicit style name

There’s another way to inherit styles/themes, the implicit way. Instead of setting a parent attribute, just prefix your new style/theme with the name of its parent and a point. Example:

But this is where this method gets subtle:

  • The Parent style/theme needs to exist: Theme.LE_THEME.NoActionBar will cause an error if Theme.LE_THEME doesn’t exist.
  • The Parent style/theme cannot be an Android default style/theme. It means that you cannot create <style name="Theme.Holo.LE_THEME> because the implicit parent is Theme.Holo and it’s not yours. But you can create <style name="Theme.Holo.LE_THEME parent="@android:style/Theme.Holo"> as it is explicit inheritance.
  • When you refer to a style/theme in Java, all the points . are replaced by underscores _. The latter theme’s Java equivalent would then be R.style.Theme_Holo_LE_THEME.
Android Holo official colors

Android Holo official colors

What does a theme specify?

Now we know the difference between a theme and a style, we know where to use each of those, we know how to define and name them, by inheritance or not. And we know every style/theme defines a certain number of properties, or attributes. But what are these attributes?

Learn from the source code

Let’s focus on the themes first.

The complete list of attributes a theme can define is available here. There are no less than 218 different attributes. The Android source code allows us to see the definition of the Android default themes, so let’s take a sample of Holo, from themes.xml (as of June 2014):

(This file being from Android source code, and therefore internal, it doesn’t use the android: prefix for the attributes name. But you have to use it when you define your own themes.)

This is just a short snippet of the whole Holo theme definition but everything important is here:

  • Let’s start by the end. Lines 22 to 24 are the reference of widget styles. It’s easy to understand: that’s where you say that your theme will use this style for all its ListViews, that other for all its TextViews, etc. All common widgets have an attribute like this.
  • Lines 17 to 19 are attributes concerning the window itself, typically these are the one you’ll touch as soon as you design a special activity: dialog or transparent window, for instance.
  • Lines 3 to 14 define the appearance of the different types of text: size (small/medium/large), importance (primary/secondary/tertiary) and color variant (normal/inverse), all the possible appearances of the texts in your theme are defined here.
  • The most interesting here is the value these attributes have. You can of course hardcode dimension values, booleans, etc., or reference drawables or colors. But mostly you’ll like to reference styles to be used in your theme. Two ways to do it:
    • Direct reference to a style
      It’s easy: you simply say that all your ScrollViews will use the style Widget.Holo.ScrollView.
    • Use the same style as another attribute
      textColorPrimary is a direct reference, but editTextColor simply says “use the style defined in the attribute textColorPrimary of this theme”.

Theme attributes

This part is important, or maybe should I say essential. The resources identified by ?android:attr/ are theme attributes. They refer to an attribute as defined in the current theme. The android: prefix can be misleading but it simply means that this theme attribute’s name has been defined in Android, but its value as defined in the current theme will retrieved.

Let’s say you have a custom layout in which you define a textView like this:

If you display this layout in an activity with theme A, the style LE_STYLE_A defined in

will be used.

If you display this very same layout in an activity with theme B, the style LE_STYLE_B defined in

will be used.

What does a style specify? Or the power of theme attributes

We know how a theme references the use of styles for its widgets/text appearances/etc. Let’s take a look at the other side now. How are these styles defined? Here is a sample of Holo styles, from styles.xml (as of June 2014):

As you can see, these Holo styles simply use their parent style without overriding anything. And the default styles only define references to theme attributes (textColorPrimary, textAppearanceSmall, …). And this is where the power of theme attributes is revealed! You can see that the default TextView widget style does not hardcode any property concerning its color, text size or whatever. It relies completely on theme attributes, which means each TextView will be customised by the theme it will be displayed in!

Now let’s practice. Let’s say you want to create a custom theme, in which you’ll just change one thing: the small texts will be 25sp instead of the default 14sp (it’s a theme for your grandmother), all the rest will be based on the DeviceDefault theme. All you have to do is:

In granny_themes.xml:

In granny_styles.xml:

Just set this Theme.Granny in your Manifest and this is it! Immediately, all the widgets that use the small text appearance (including the default TextView) will display a size of 25sp. Without any modification of these widgets’ styles. Neither do you need to hardcode a text size in your layouts.

And you could change the background of your ActionBar, for instance, exactly the same way. Simply reference your custom style in your theme’s android:actionBarStyle.

Conclusion

From my experience, it takes quite a lot of time to understand what is a text appearance, what is a theme attribute, how to inherit styles, and even more time to get to use those concepts properly. The benefit, though, is tremendous: you don’t lose any more time creating standalone styles. Instead you’re able to customise deeply your app, all at once.

As a final word, let me share some tips:

  • Always make your custom styles/themes inherit DeviceDefault themes instead of Holo. DeviceDefault is the default from API level 14 and will ensure the best look across a HTC, a Samsung, a Sony, a Nexus, etc. device.
  • Follow Android naming conventions Theme.LE_THEME.Light, Widget.LE_THEME.TextView, etc. This will make your code much more readable and maintainable.
  • Eclipse text completion works terrible with theme and style attributes. To know what attribute you can set on a theme, or a TextView style or a TextAppearance style, you’d need to check this reference R.styleable or directly the reference for the widget you want to customise in the section XML Attributes and Inherited XML Attributes (example in the ScrollView reference).

That’s all folks. Start playing with sizes, colors, and other styles to control the look and feel of your apps!

David,

facebooktwittergoogle_plusredditpinterestlinkedinmail

Have something to add?

Loading Facebook Comments ...

Leave a Reply

*