The following is the first few sections of a chapter from The Busy Coder's Guide to Android Development, plus headings for the remaining major sections, to give you an idea about the content of the chapter.


Defining and Using Styles

As noted in an earlier chapter, Android offers styles and themes, filling the same sort of role that CSS does in Web development. In that earlier chapter, we covered the basic roles of styles and themes, plus introduced the three classic theme families:

In this chapter, we will take a slightly “deeper dive” into styles and themes, exploring how you can create your own and apply them to your app’s UI.

Styles: DIY DRY

The purpose of styles is to encapsulate a set of attributes that you intend to use repeatedly, conditionally, or otherwise wish to keep separate from your layouts proper. The primary use case is “don’t repeat yourself” (DRY) — if you have a bunch of widgets that look the same, use a style to use a single definition for “look the same”, rather than copying the look from widget to widget.

And that paragraph will make a bit more sense if we look at an example, specifically the Styles/NowStyled sample project. This is a trivial project, with a full-screen button that shows the date and time of when the activity was launched or when the button was pushed. This time, though, we want to change the way the text on the face of the button appears, and we will do so using a style.

The res/layout/main.xml file in this project has a style attribute on the Button:

<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/button"
  android:text=""
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  style="@style/bigred"
/>

Note that the style attribute is part of stock XML and therefore is not in the android namespace, so it does not get the android: prefix.

The value, @style/bigred, points to a style resource. Style resources are values resources and can be found in the res/values/ directory in your project, or in other resource sets (e.g., res/values-v11/ for values resources only to be used on API Level 11 or higher). The convention is for style resources to be held in a styles.xml file, such as the one from the NowStyled project:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <style name="bigred">
    <item name="android:textSize">30sp</item>
    <item name="android:textColor">#FFFF0000</item>
  </style>
</resources>

The <style> element supplies the name of the style, which is what we use when referring to the style from a layout. The <item> children of the <style> element represent values of attributes to be applied to whatever the style is applied towards — in our example, our Button widget. So, our Button will have a comparatively large font (android:textSize set to 30sp) and have the text appear in red (android:textColor set to #FFFF0000).

Just defining the style and applying it to the widget gives us the desired results:

The Styles/NowStyled sample application
Figure 186: The Styles/NowStyled sample application

Elements of Style

There are four elements to consider when applying a style:

Where to Apply a Style

The style attribute can be applied to a widget, to only affect that widget.

The style attribute can be applied to a container, to affect that container. However, doing this does not automatically style its children. For example, suppose res/layout/main.xml looked instead like this:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    style="@style/bigred">               
  <Button
    android:id="@+id/button"
    android:text=""
    android:layout_width="match_parent"
    android:layout_height="match_parent"
  />
</LinearLayout>

The resulting UI would not have the Button text in a big red font, despite the style attribute. The style only affects the container, not the contents of the container.

You can also apply a style to an activity or an application as a whole, though then it is referred to as a “theme”, which will be covered a bit later in this chapter.

The Available Attributes

When styling a widget or container, you can apply any of that widget’s or container’s attributes in the style itself. So, if it shows up in the “XML Attributes” or “Inherited XML Attributes” portions of the Android JavaDocs, you can put it in a style.

Note that Android will ignore invalid styles. So, had we applied the bigred style to the LinearLayout as shown above, everything would run fine, just with no visible results. Despite the fact that LinearLayout has no android:textSize or android:textColor attribute, there is no compile-time failure nor a runtime exception.

Also, layout directives, such as android:layout_width, can be put in a style.

Inheriting a Style

You can also indicate that you want to inherit style attributes from another style, by specifying a parent attribute on the <style> element.

For example, take a look at this style resource:


<?xml version="1.0" encoding="utf-8"?>
<resources>
  <style name="activated" parent="android:Theme.Holo">
    <item name="android:background">?android:attr/activatedBackgroundIndicator</item>
  </style>
</resources>

(note: in some renditions of this book, you may see the <item> element split over two lines — this is caused by word-wrapping, as this element should be all on one line)

Here, we are indicating that we want to inherit the Theme.Holo style from within Android. Hence, in addition to all of our own attribute definitions, we are specifying that we want all of the attribute definitions from Theme.Holo as well.

In many cases, this will not be necessary. If you do not specify a parent, your attribute definitions will be blended into whatever default style is being applied to the widget or container.

That ?android:attr looks a bit bizarre, but we will get into what that syntax means in the next section.

The Possible Values

Typically, the value that you will give those attributes in the style will be some constant, like 30sp or #FFFF0000.

Sometimes, though, you want to perform a bit of indirection — you want to apply some other attribute value from the theme you are inheriting from. In that case, you will wind up using the somewhat cryptic ?android:attr/ syntax, along with a few related magic incantations.

For example, let’s look again at this style resource:


<?xml version="1.0" encoding="utf-8"?>
<resources>
  <style name="activated" parent="android:Theme.Holo">
    <item name="android:background">?android:attr/activatedBackgroundIndicator</item>
  </style>
</resources>

Here, we are indicating that the value of android:background is not some constant value, or even a reference to a drawable resource (e.g., @drawable/my_background). Instead, we are referring to the value of some other attribute — activatedBackgroundIndicator — from our inherited theme. Whatever the theme defines as being the activatedBackgroundIndicator is what our background should be.

This portion of the Android style system is very under-documented, to the point where Google itself recommends you look at the Android source code listing the various styles to see what is possible.

This is one place where inheriting a style becomes important. In the example shown in this section, we inherited from Theme.Holo, because we specifically wanted the activatedBackgroundIndicator value from Theme.Holo. That value might not exist in other styles, or it might not have the value we want.

Themes: Would a Style By Any Other Name…

The preview of this section was lost due to a rupture in the space-time continuum.

What Happens If You Have No Theme

The preview of this section was traded for a bag of magic beans.

Android Studio’s Theme Editor

The preview of this section was whisked away by a shark-infested tornado.