Knowing how to take advantage of both Styles and Themes in Android can save you a lot of time. Not only do they lead to better looking user interfaces, but they primarily save you the work of writing lots of duplicate XML. There is a big difference between a Style and a Theme, but it’s easy to grasp. A Style will only affect the View or Widget it is applied to but a Theme will affect all Views and Widgets across your app. Themes are also only declared once – in your app’s (or build’s) manifest. Below we will dive in to the differences in depth. We’ll also discuss how to create Styles or Themes of your own.
A style is a set of XML attributes that can be applied to a View. In an Android project, styles are located in res > values > styles.xml. You can also create an API qualified styles.xml file in case some attributes would require a higher minimum API level. To create a new style, open the styles.xml file and give your new style whatever name you want. Within that style, you include the attributes you want it to provide within an item element. For example, if you want a style which will make a widget’s text red, it would look like this.
<style name="RedText"> <item name="android:textColor">#ff0000</item> </style>
This is quite a basic style as it contains only one attribute. Though, a very powerful feature styles allow us to take advantage of is – inheritance. This concept works similarly to how it does in Object Oriented Programming (OOP) . Like an Object in Java, we can create styles which inherit or override their parent’s attributes.
<style name="RedText.Title"> <item name="android:textSize">48sp</item> <item name="android:fontFamily">cursive</item> </style> <style name="RedText.Title.Bold"> <item name="android:textStyle">bold</item> </style>
This is an example of styles inheriting from each other. RedText.Title has values for textSize and fontFamily. This means that if we apply this style to a widget, it will have a cursive font plus a size of 48sp. On top of this, the colour of the text will be red. The way we inherit from the RedText style is by simply using a . (dot/period) to say we want to inherit attributes from RedText. You can also declare a parent by specifying it in the style tag like so.
<style name="Title" parent="RedText"> <item name="android:textSize">48sp</item> <item name="android:fontFamily">cursive</item> </style>
I personally find it much easier to understand a style’s hierarchy by using the . method (as in RedText.Title). By now, you should be able to understand how powerful styles can be when it comes to customizing your widgets. If we wanted to apply this style to a widget we would do the following.
<TextView style="@style/RedText.Title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" />
All we do is provide the style attribute and point to the name of our chosen style, in this case it’s RedText.Title. The result should look like the following. (Note: Other attributes in your TextView will vary depending on which parent layout you choose to use. The above is a TextView in a ConstraintLayout.)
Unlike a Style, a theme will apply its attributes across your entire app. This is great if you don’t want to go through the process of manually applying a style to every widget in every layout. For example, in a theme, you can specify that “all TextViews should be of style x”. Your app’s theme is declared in the manifest file. You can find the theme attribute within the application tag. It will look something like this.
<manifest <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> </application> </manifest>
When you first create a new Android project, it is given the default theme of AppTheme. If you take a look at the styles.xml file, you can see this is where AppTheme is defined. AppTheme is inheriting from Theme.AppCompat.Light.DarkActionBar in this case.
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style>
A theme can also be called a style since they are defined in the same place. However, a theme will specify different attributes than styles do. A theme’s attributes are accessible from all widgets, while a style’s attributes pertain only to the widget it is applied to. For example, our toolbar will look at the colorPrimary attribute in order to set its background colour. colorPrimary, colorPrimaryDark and colorAccent are used to specify the universal colour branding of your app.
Theming Background Colour
We can override or add to a theme’s attributes the same way we would a style. Finding the attributes we wish to override can be tough. At times you will need to re-run your app to make sure your changes are what you intended. This is due to the fact there is little documentation on theme attributes.
For this example, let’s look for a way to change the background colour of our entire app. You can navigate up your theme’s hierarchy by ctrl-clicking on its parent. You will notice that the few initial themes do not have any attributes, but only declare a parent. Keep going until we find an attribute which seems to change the background colour. Also, a theme may have different versions in order to take advantage of newer features not available on older API releases. You will want to choose non-resource qualified files as shown in this image.
Continuing on, eventually you will come to a theme called android:Theme.Light. This is where the attribute responsible for changing the background colour of your theme lives. It is called, windowBackground. You may also notice that Theme.Light is preceded by the android: namespace. This is due to the fact that this theme resides in the Android OS itself, and not the AppCompat library. We will want to override this in our base theme, AppTheme.
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> <item name="android:windowBackground">@color/colorPrimary</item> </style>
I chose to gave it the colour of AppTheme’s colorPrimary attribute. This probably isn’t a good colour scheme you would want to use in a production app, but you get the idea. What if wanted to change more than just the background colour. How about changing the way a certain widget looks across our entire app?
If we want to change the way a certain widget looks throughout our app, we need to override another attribute. In this case, we will apply our RedText style to all TextViews. This will result in all the text in our app being red. Before we do this, you should also remove the style attribute from the TextView we used in the earlier example. Once you’ve done that, you can begin navigating through the theme’s hierarchy. Eventually you will find the root, simply called Theme. This is where the attribute for changing TextView style lies – textViewStyle. We can override this attribute in our theme.
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> <item name="android:textViewStyle">@style/RedText</item> </style> <style name="RedText" parent="android:Widget.TextView"> <item name="android:textColor">#ff0000</item> </style>
You will notice we also declare a parent for our RedText style now. Why? This is because you want all TextViews to inherit the same attributes any other normal TextView would, but then override it with your own. In this case, any attributes we put in our RedText style. This is also the same style textViewStyle was set to within Theme.
Having knowledge of both styles and themes can save you a lot of work. Not only that, they can drastically change the look of your applications in a single line. When I started learning Android, I had no idea what styles and themes really were. I remember I would write mountains of duplicate XML code in my layouts, yet all my widgets looked more or less the same. If I only knew how to advantage of styles back then. Luckily for you, now you have no excuse to make the same mistake I did!