Values.xml : Breaking down the scary creature

Saurabh Arora
AndroidPub
Published in
6 min readFeb 17, 2018

--

Given styles’s widespread use in Android Platform, it is surprising that there isn’t sufficient documentation from Google about how to understand and use styles on your views. I have come across multiple questions and have met various developers who have difficulties in grasping this concept. Looking at an app`s styles.xml file or even the platform/support libraries values.xml file can be daunting. Through this post, I’ll try to demystify styles and hopefully after the end of the post, you’ll be a lot more comfortable in finding you way around those scary looking files and be more confident in being able customise the look and feel of your views.

A quick intro

A style is just a collection of attributes that can be applied to a view. When those collection of attributes (style) is applied to a window, such as an activity, it is called a theme. Beginning with Android L, themes can also be applied to a view but we’ll get to that later.

Before we go ahead, let us also tackle attributes. An attribute is like a pointer to a value defined in your theme. By changing or customising the theme, you can change the attributes value as well. There are mostly two types/ways to use a attribute:

  • ?android:/attr : Values built in inside the Android SDK
  • ?attr/: Values defined which we have defined or the values defined by other libraries such as the support library, design library, etc.

Think of ?as de-referencing the attribute to get the value pointed by the attribute and not the actual attribute itself.

In the above, we have defined an AppTheme, which we have applied to the MainActivity. All the view and windows (such as an AlertDialog) inflated by the activity, will use the values referenced by those attributes.

<item name="alertDialogTheme">@style/MyDialog</item>

The above implies that we are setting the the value of the attribute alertDialogTheme to a style that we have defined. Now when we create an AlertDialog with a context of the MainActivity, the alert dialog will use our MyDialog theme.

Style Inheritance

Style inheritance is just like regular inheritance. You can share the attributes and override/add what you need. There are two ways through which you can specifiy inhertance:

  • Explicit Inheritance: You can add a parent attribute to the style element to specify which style your current style inherits attributes from.
<style name="RedBackgroundStyle">
<item name="android:background">@color/red</item>
</style>

<style name="AlphaRedBackgroundStyle" parent="RedBackgroundStyle">
<item name="android:alpha">0.5</item>
</style>
  • Implicit Inheritance: This use the . pattern to define the parent. Using the . pattern, you can easily chain styles together and keep on inheriting attributes.
<style name="RedBackgroundStyle">
<item name="android:background">@color/red</item>
</style>

<style name="RedBackgroundStyle.Alpha">
<item name="android:alpha">0.5</item>
</style>

<style name="RedBackgroundStyle.Alpha.Lines">
<item name="android:maxLines">2</item>
</style>

The RedBackgroundStyle.Alpha.Lines will have a red background with 0.5 alpha channel and no more than 2 lines of text.

Quick Tip: The documentation mentions that you can’t inherit Android built-in styles using the dot notation, as it doesn’t reside in your namespace. This should not be confused with the support library styles since they belong to the “app” namespace and hence can be directly accessed.

<style name="TextAppearance.Demo">
<!--This won't work as it is an Android Style-->
</style>

<style name="TextAppearance.AppCompat.Demo">
<!--This is okay as you are using a support library style-->
</style>

Be careful to not combine the two styles together. The support library does that, but I would not recommend that for most developers. This can easily cause headaches. Consider the following example:

<style name="MyTabLayout" parent="Widget.Design.TabLayout">
<item name="tabIndicatorColor">@color/red</item>
</style>

<style name="MyTabLayout.Another" parent="Widget.Design.TabLayout">

</style>

The TabLayout to which you would apply the MyTabLayout.Another style, would not have the indicator color as red. This is because, the explicit style (which would have defined a default value of the tabIndicatorColor) attributes are always the winner unless overriden by the child style.

Deciphering the Styles file

Since the support library is the de-facto component in all apps, we’ll run through it’s styles file. Fire up Android Studio and search for values.xml and select the one contained inside the appcompat-support library.

Let’s search for Theme.AppCompat.Light.DarkActionBar. As you can see, this inherits from Base.Theme.AppCompat.Light.DarkActionBar. By navigating up the parent hierarchy, you should eventually reach Base.v21.Theme.AppCompat.Light. Here you can see most of the attributes that this theme offers and what their default values are. If you go through it carefully, you should also be able to spot the alertDialogTheme attribute (it’s under Base.v7.Theme.AppCompat.Light) , which is what I used in my first example above 😉

Now, if you are ever confused why your view looks a certain way or need to modify a certain attribute, you can quickly look up the theme and see what style has been applied to your view. To see what attribute a view uses to get its default style, you can look it up in the source code of the view. Here is an example for SeekBar and here is another example of a TextInputLayout (The corresponding style file for this will be in the design library package). In the below GIF, you see how I quickly figure out the color of the progress track of the SeekBar

The values.xml files is huge and is just the tip of iceberg. Since android design language has changed over the years, the parent styles are distributed across API levels. Hence, I would recommend you understand how to read it and explore the values.xml file when you have some questions. It probably isn’t a good idea to try to go through it in one go, unless you are Chris Banes 😉

Android L Changes

Beginning with Lollipop (API Level 21), a theme could also be applied to a view. This change was also added to the support library. This opens up interesting possibilities as it allows us to change attribute values at the view level, thereby not affecting the attribute values at the activity level.

As a contrived example, let’s say you have a scenario in which you have a CheckBox and a SeekBar in the same activity and you want them to have different colors. As we saw above, the SeekBar’s track drawable uses the colorControlActivated attribute as its track color. Checkbox also uses the same attribute for it’s checked state color. Now if you dig through the values.xml file of the appcompat-support library, you’ll notice that the colorControlActivated attribute refers to the value of the colorAccent attribute.

`colorControlActivated` same as `colorAccent` attribute

Now if we want to change the track color of the SeekBar, we can just create a new theme which changes the value of the colorControlActivated or the colorAccent attribute to our chosen color and apply that theme to our SeekBar. You cannot do this via a style, since colorControlActivated is an attribute and you can only change the value of an attribute through a theme and not through a style.

Use theme to alter the Seekbar track
SeekBar color changed while Checkbox still uses the activity theme

This is much easier and future proof than copying over the SeekBar track drawable into your app’s resources directory and then making changes in it. The ability to use a theme on the view is what makes this all possible.

I have tired to touch all the pain points to demystify styles and I hope this will make you much more confident when you have to deal with them again. In a follow up post, I’ll try to combine all three (styles, themes and attributes), to build an action view for a menu item, in a manner that it looks just like the native menu item and automatically adapts across all OS versions and screen sizes. The post will be linked here when it is ready.

If you feel that I missed out on something or made some mistake or have suggestion on how I could improve, feel free to reach out to me on twitter. If you liked this post or learned something, please remember to applaud it by pressing the 👏 button and do share it 😃

--

--