Themes & Styles in Android

An important part of designing user interfaces in the Android framework is to use themes and styles as much as we can to separate design…

Themes & Styles in Android

An important part of designing user interfaces in the Android framework is to use themes and styles as much as we can to separate design logic and behaviors into a single manageable place.

First, let’s start with the differences between themes and styles. Why they are called the way they are?

Styles

A style is a set of attributes of an individual view. It is declared in res/values, usually named styles.xml, but you can change it to whatever you want.

Most of the predefined style names usually start with Widgets. For example, styles in MaterialComponents are in Widget.MaterialComponents.

To apply the style to all buttons in our app, we need to use a theme which we will talk about it in a second.

After setting style in AppTheme, we will see all of our buttons in the app changed to be outlined. Any view which is inflated inside AppTheme will have the style — Widget.MyApp.Button.OutlinedButton

Style Inheritance

One of the cool things about styles is the ability to inherit from any style. As you can see in the example above, there is a parent keyword which we used to specify where to inherit from. There are two types of style inheritance. Explicit and Implicit are the same, it’s just different in syntax.

  • Explicit inheritance — specify parent keyword.
  • Implicit Inheritance — Using dot notions.

Both methods are handy in different cases.

  • Mixed Inheritance (Unofficial)— A combination of implicit and explicit

Question: Which one does YourStyle inherits from?

Answer:

If parent keyword is specified, the implicit inheritance will be ignored, so YourStyle inherits from HerStyle.

In MaterialComponents, they use this technique to classify themes, text appearances and styles into different Base style’s names such as Base Widget Theme TextAppearance ThemeOverlay and more.

It’s a best practice to put your style there since it will give save your time to try to distinguish which one is which.

By convention,

<StyleType>.<YourAppName>.<Widget>.<Behavior>.<Inherited Behavior>

…. So on and so on

For example,

Assume that my app’s name “Medium”, so to define a custom style for a text view, we should name it as:

Widget.Medium.TextView

Widget.Medium.TextView.StylishTextView

Widget.Medium.TextView.StylishTextView.InvertedStylishTextView

If it is a button

Widget.Medium.Button

Widget.Medium.Button.UnelevatedButton

Widget.Medium.Button.UnelevatedButton.CutCornerButton

also, if it’s a text appearance it should be

TextAppearance.Medium.TextAppearanceBody

TextAppearance.Medium.TextAppearanceHeading1

TextAppearance.Medium.TextAppearanceDisplay2

Finally, ShapeAppearance. You might be asking yourself, what the heck is it? Well, shape appearances are similar to text appearances, but it’s for the shape of an individual view rather than text format.

A cut-corner button

To achieve this shape, we have to declare a shape appearance for it. Read more detail about Shape Appearance here.


Themes

A theme is used to style the view hierarchy. When you apply a theme to a view, it will then apply those to all its children. On the other hand, a style is just for a single view. Themes can be used to change the value of the attributes to be the different values we prefer. For example, if we want to change our app accent color for our entire activities, we will definitely use a theme to achieve that. I am pretty sure that you’re familiar with that!

As you can see in the example above, we use a theme to change theme attribute and property values. Not only colors, but we can also change almost everything including font family, text appearances, button styles, text styles, and more.

Theme Attributes

Changing some values of our app globally would be a pain if we didn’t have Theme Attributes. By defining an attribute that we can refer to later in the app or XML is necessary as changing an attribute in the theme will affect your whole app, which is cool isn’t it? That’s why Chris Banes and Nick Butcher encourage us to always use theme attributes whenever possible.

Here is a list of some useful theme attributes I knew and have been used for awhile

Color Attributes

  • ?attr/colorPrimary
  • ?attr/colorPrimaryVariant
  • ?attr/colorSecondary
  • ?attr/colorSecondaryVariant
  • ?attr/colorOnPrimary
  • ?attr/colorOnSecondary
  • ?attr/colorOnSurface
  • ?attr/colorSurface
  • ?android:attr/texColorPrimary
  • ?android:attr/textColorSecondary
  • ?attr/colorControlNormal
  • ?attr/colorControlActivated
  • ?attr/colorControlHighlight

Style Attributes

  • ?attr/appBarLayoutStyle
  • ?attr/materialButtonStyle
  • ?attr/materialButtonOutlinedStyle
  • ?attr/toolbarStyle
  • ?attr/navigationViewStyle
  • ?attr/recyclerViewStyle
  • ?attr/coordinatorLayoutStyle
  • ?attr/checkboxStyle
  • ?attr/materialCardViewStyle
style attribtues

Text Appearance Attributes

  • ?attr/textAppearanceButton
  • ?attr/textAppearanceBody1
  • ?attr/textAppearanceBody2
  • ?attr/textAppearanceHeadline1
  • ?attr/textAppearanceHeadline2
  • ?attr/textAppearanceHeadline3
  • ?attr/textAppearanceHeadline4
  • ?attr/textAppearanceHeadline5
  • ?attr/textAppearanceHeadline6
  • ?attr/textAppearanceSubtitle1
  • ?attr/textAppearanceSubtitle2
  • ?attr/textAppearanceOverline
  • ?attr/textAppearanceCaption
  • ?attr/textAppearanceListItem
  • ?attr/textAppearanceListItemSmall
  • ?attr/textAppearanceListItemSecondary

Shape Appearance Attributes

  • ?attr/shapeAppearanceLargeComponent
  • ?attr/shapeAppearanceMediumComponent
  • ?attr/shapeAppearanceSmallComponent

Dimens Attributes

  • ?attr/actionBarSize
  • ?android:attr/disabledAlpha
  • ?attr/dialogCornerRadius

See more in this article by @crafty

Theme Attributes and Dark Mode

Light and dark mode are now becoming the importance of every mobile app, so in order to address that we have to design our app carefully. If your app is not created with theme attributes in mind I will be a pain to migrate from light to dark and vice-versa.

⚠️ Avoid using hardcoded values

You might be thinking using @color/colorPrimary is a good option but it’s not even though it is better than using a plain hardcoded text. The best option is to use a theme attribute over @colors/my_color_name.️