ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Follow publication

Photo by Steve Johnson on Unsplash

Theming basics in Android

Suleyman Fatih Giris
ProAndroidDev
Published in
8 min readMay 7, 2021

Theming the app could be one of the most confusing topics in Android development. It is getting harder to maintain the styles of your components and theming of your app while the project is getting bigger. If you don’t have a good design system, you might have inconsistent designs and colors in the app. Having a good understanding of styling & theming will help you create UIs consistent across the app. Also if you are thinking about migrating to Compose, a poor design system might create more complexity.

Having a good design system requires to have a proper styling & theming setup. This helps us to have consistent and reusable styles for our components. But how do we actually have a proper styling & theming setup?

Well, this question does not have only one answer but it can be divided into 5 pieces.

  • Attributes
  • Default style
  • Style vs Theme
  • Theme overlay
  • TextAppearance

Attributes

Everything starts with an attribute. Without attributes, nothing in XML would have any characteristic that we can define. Attributes are named values that have their definition in attrs.xml file. An attribute can be defined for a view as well as a theme. For instance, android:layout_width attribute is a view attribute whereas colorPrimary is a theme attribute.

A view attribute is set in the view’s XML either by setting directly on the view tag or indirectly by using style(will be mentioned later). Let’s look at how we can set the background of a button to red with android:backgroundTint view attribute.

Note: In order to access the built-in attributes, android prefix is used.

Let’s say you want to change its background to white. You can do this by setting the android:backgroundTint attribute to white.

This is fine if you will only change a single button. But what about if you would like to change all the red buttons to white? It can be achieved by:

  • Using a theme attribute for android:backgroundTint
  • Creating and applying a style to all buttons

A theme attribute is an attribute that does not belong to any view and can be changed at the theme level.

In order to use a theme attribute for android:backgroundTint, let's first define a custom theme attribute called myButtonBackground in attrs.xml.

Adding a custom theme attr

An attribute’s type is set with format field. The format can be given as a single type or multiple, for example with android:background format="reference|color" which accepts both references to a drawable resource (“reference”) and color (“color”).

You can now use myButtonBackground attribute to set your button's background. But before that, you need to set a value to myButtonBackground. It must be defined either in the theme or the theme overlay that’s going to be used.

Setting the value of a theme attr

Then you can use this attribute to set the background of your buttons.

Setting the background of a button with a custom attr

If you change the attribute value, then the background of all buttons using ?attr/myButtonBackground attribute as its background will change. Alternatively, you can use ?myButtonBackground as a short hand instead of ?attr/myButtonBackground.

But setting android:backgroundTint to myButtonBackground for all buttons might be overwhelming. In order to overcome this, we will be creating a style and applying it to all buttons using a default style.

Default style

Have you ever noticed that even if you don't give any background to the button, you get a background drawable? This is because the Button component has a default style as any other view. A default style is a style that is used as a view’s base style.

Let's check the button's default style.

Button’s default style is set through R.attr.buttonStyle theme attribute. So it means that you can change the default style of all buttons in your app with this attribute.

Let’s change the default style of the button in our theme so that the background will be red.

Setting the button default style with buttonStyle attribute

Then whenever you create a button, you will get this.

A button with a red background

Isn’t this more like a text with a red background? This is because MyButton style does not inherit from any styles. For this reason, all buttons will only contain the background attribute in their default style. Let’s check how the default button style looks like in AppCompat.

Default button style in AppCompat

As you can see, these attributes are the base style for the button. Let’s give Widget.AppCompat.Button as a parent to the MyButton style and change the background attribute with backgroundTint since we only want to change the color not the drawable.

Setting the parent style of MyButton

Then we get a button with a red background 🎉.

A button with a red background tint

Style vs Theme

We have mentioned both style and theme but what is the difference between them? Both style and theme are set of attributes but the difference is what they apply to. Styles are meant to be applied to views and themes to an activity or entire app. Because of this reason, a style should only contain view attributes and a theme should only contain theme attributes.

You can change the style of a view in 3 ways:

  • Changing the view attribute on the layout file
  • Creating a new style and applying it with views style attribute on the layout file
  • Specifying a default style

Let’s see how we can change the background of a button in the layout file.

Changing a background of a button in the layout file

Now let’s check how we can create a style and apply it to this button.

A button style that has a custom background drawable
Setting a custom style to a button

Applying a style only takes the view attributes into an account. If you try to set any theme attribute inside MyButton style, it will not work. In order to give an example, we will:

  • Use colorPrimary theme attribute inside background drawable of the button
  • Change the value of colorPrimary inside the MyButton style
Background drawable which uses colorPrimary attribute
Changing the colorPrimary theme attribute inside the button style

Then even though we set the primary color as red, we get a button with a purple background.

Button with a purple background

This is because a view only knows about its own attributes; Button isn’t aware of the colorPrimary attribute so it’s ignored.

A view gets the view attributes from the layout file or the style attribute. If a view style includes a theme attribute, it will be ignored.

Then, how do we actually change the theme attributes only for a single view? Here is where theme overlay comes into play.

Theme Overlay

Theme overlay is a technique used to override theme attributes for any view or view group. Theme overlays are very useful when you update the theme of a specific part of your app.

Applying a theme overlay consists of 2 steps:

  • Create a style that consists of theme attributes desired to be changed
  • Apply this style on the layout file by using android:theme or programmatically by using ContextThemeWrapper

Let’s continue with the aforementioned scenario where we are changing the button background color by the colorPrimary theme attribute. First, we need to create a style for a theme overlay where we set colorPrimary.

A theme overlay for a button

A theme overlay does not have any parent.

Furthermore, it is better to start naming the style with ThemeOverlay since it will make it easier to distinguish from the other styles. This naming technique is used in Material Components and AppCompat too.

Let’s apply this overlay to a button in the layout file.

Applying a theme overlay using android:theme attribute

Bear in mind that if a theme overlay is applied to a view group, it will apply to all of its descendants too. In other words, the theme of every view group’s descendant is overlaid when a theme overlay is applied to a view group.

Applying a theme overlay to a view group

We can also apply a theme overlay programmatically wrapping the context of the view with ContextThemeWrapper.

Using ContextThemeWrapper to apply a theme overlay

ContextThemeWrapper creates a new context (wrapping the given one) with its own theme.

TextAppearance

TextAppearance is a class that contains data for only styling the TextView`s text-related attributes (For instance textColor, textSize but not view related attributes like maxLines or drawableTop etc.).

TextAppearance is set by android:textAppearance attribute on the TextView. android:textAppearance attribute works the same with style attribute. The main difference is the precedence order of them. style takes precedence over android:textAppearance meaning that style will always override the common attributes.

You might be asking why do we need it since we can give everything in style? The answer is having a way to set only text-related attributes makes it reusable for all TextViews whilst leaving the style attribute free.

For instance, let’s create a text appearance for a header.

Header text appearance

Now, you can use this text appearance to make any TextView a header.

Using TextAppearance.StylesNThemes.Header style as a text appearance

As you can see, the style attribute for TextView is free and can be used to customize other view attributes. You can also set android:textAppearance by creating a style.

Let’s create a single-line header style.

Single line header style

You can now set this style using style attribute and reuse this style for any text.

Applying single line header style to a text view

If you want to dive deep into text appearances and the precedence of styles more, I highly recommend you to read this article.

Conclusion

Attributes are a key concept in styling & theming. Use view attributes to style a view and theme attributes for the application, Activity, or view hierarchy. If you want to change the style for all instances of a given view type throughout the app, default styles are the way to go. Theme overlays are used to override the theme attributes and you can even use them for views in a given view hierarchy. Text appearances can help you to shape your TextViews text-related attributes with android:textAppearance, while leaving style attribute free.

Thanks Ataul Munim and Nick Butcher for the reviews.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Responses (2)

Write a response