Building Better App UI Architecture- Android Themes

January 13, 2020
Building Better App UI Architecture- Android Themes

Our last post focused on optimizing UI system implementation by breaking down design into smaller pieces, identifying the UI elements and components, and using protocol-oriented programming in iOS. As I mentioned here.

This time around, we’ll give Android the spotlight by building a sample app that can switch themes using respective dark mode. We’ll also discuss approaches that can make Android UI development more efficient.

Theme and Style in Android

Generally we follow themes and styles as much as possible for consistency. Before diving into the sample app, let’s see how the Android developer guide defines themes and styles:

  • A style is a collection of attributes that specify the appearance for a single View. A style can specify attributes such as font color, font size, background color, and much more.
  • A theme is a type of style that's applied to an entire app, activity, or view hierarchy—not just an individual view. When you apply your style as a theme, every view in the app or activity applies each style attribute that it supports. Themes can also apply styles to non-view elements, such as the status bar and window background.

The bottom line? Applying a style to a view impacts only that view and not its children. However, if you apply a theme to a view it will be applied to all view/non-view elements.

Dark Theme

Starting with Android Q, users can switch the device into dark theme via system settings -> Display -> Dark theme. To support the dark theme functionality, you must set the app’s theme to inherit from a DayNight theme.

Google recommends updating the app theme to inherit from the Theme.MaterialComponents.DayNight (or one of its descendants). For example:

`xml `

In most cases, switching to dark theme doesn’t just about inverting the white into black:

There are several principles we need to follow:

  • Darken with grey.
  • Apply limited color accents in dark theme.
  • Meeting the accessibility color contrast standards.

So we also need to define separate theme attributes within each theme, which can be inherited from style name="AppTheme" parent="Theme.MaterialComponents.Light" in res/values/themes.xml file:

`xml `

Then define your dark theme in res/values-night/themes.xml:

`xml `

For most apps that use AppCompat themes, if you want to incrementally add material components you have to add the theme attributes to the existing app theme. You can find all new attributes here.

From Android 10 onwards you can set android:forceDarkAllowed="true" in the activity's theme, so that even the app without DayNight can automatically apply dark theme. Just make sure everything looks right before you turn it on.

Multiple themes with dark mode

The sample we’re going to build is a bit different. In this case, we’re planning on several themes.

This means having several DayNight themes. Let’s define our basic theme first:



colorControlDisabled and colorControlDisableDark are custom theme attributes.

You can define custom theme attributes in res/values/attrs.xml like this:

`html `

Now define the red theme:

`xml `

Next, we define dark mode for the red theme:

`xml `

We can see AppTheme.Basic.Red.Dark inherits from AppTheme.Basic.Red, which overrides the attributes that need to change in dark mode:



If you’re looking to dig deeper, here are all the original attributes in AppCompat theme.

Use this same approach to define other color themes and their dark modes for “orange", “blue", “green", “purple", "teal", or whatever you decide to name it.

Next, we need to style our views. For consistency, carry out themes and styles as much as possible, and keep Android's style hierarchy in mind. The list is ordered from highest precedence to lowest to help you determine which attributes to apply:

  • Applying character- or paragraph-level styling via text spans to TextView-derived classes
  • Applying attributes programmatically
  • Applying individual attributes directly to a view
  • Applying a style to a view
  • Default styling
  • Applying a theme to a collection of views, an activity, or your entire app
  • Applying certain view-specific styling, such as setting a TextAppearance on a TextView

So, wherever we need to change the theme in our sample app, we need to apply the theme attributes. For example, using a gradient drawable gradient_background.xml as the background, will look like this:

`xml <?xml version="1.0" encoding="utf-8"?>



Now a card view with a background changed by theme:

`xml <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="@dimen/card_view_margin" app:cardBackgroundColor="?attr/themeSurface" > `

You can then define a textView like this:

`xml <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:padding="8dp" android:text="@string/app_title" android:background="?colorPrimary" android:textColor="@color/pink_600" android:textAppearance="@style/MyAppTextAppearance.Header1" /> `

The text color will always be pink_600 no matter what text color is set in textAppearance or what theme you use. For things you never want to change, apply individual attributes directly.

Okay, now that our themes and views are set up, we can call SetTheme in MainActivity.kt. Here is the code snippet:

`kotlin override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState)

if (getPreferences(Activity.MODE_PRIVATE).getBoolean("isNightMode", false)) {

when(getSavedTheme()) { -> setTheme( -> setTheme( -> setTheme( -> setTheme( -> setTheme( ->  setTheme(

} else {


} // … } `

Save/get the theme to user preference:

`kotlin private fun saveTheme(value: String) { val pref = getPreferences(Activity.MODE_PRIVATE) pref.edit().putString("theme", value).apply() recreate() }

private fun getSavedTheme(): Int { val theme = getPreferences(Activity.MODE_PRIVATE).getString("theme", BLUE) when (theme) {

ORANGE -> return
RED -> return
BLUE -> return
GREEN -> return
PURPLE -> return
TEAL -> return
else -> return

} } `

After a somewhat tedious process, our app now supports multiple themes with respective dark mode.

In app development, requirements, design, and implementation (especially UI) are prone to change. The first thing we need to keep in mind is to avoid creating styles with hardcoded values. Separating UI code by first defining theme, styles, and custom view components results in a powerful central control and reduces the amount of code and improve reusability and testability.

In the long run understanding how style/view hierarchy works within a specific operating system helps to create a clear hierarchy implementation, while ultimately making code more reusable.

Next up in our How to Build a Better App UI Architecture series: Creating a custom view in Android. We can’t wait to share our insights.

Mei Huang
Mei Huang
Software Developer

Stay in the loop with our latest content!

Select the topics you’re interested to receive our new relevant content in your inbox. Don’t worry, we won’t spam you.

Looking for a Front-End Framework? Our View On Vue

Looking for a Front-End Framework? Our View On Vue

March 15, 2021

The programming world has always had its share of opinions. Our community loves debating everything from tabs vs. spaces to Vim vs. non-Vim to which frontend framework you should use. For me, the answer almost always comes down to: “Whichever, so long as it’s consistent across your project.” End of article. Thanks for reading!

Read more
MichiganLabs named #1 iOS Development Company by MobileAppDaily
Business iOS Press Release

MichiganLabs named #1 iOS Development Company by MobileAppDaily

January 28, 2020

The report features leading iOS companies of the mobile app industry, who have made themselves known because of their exceptional app development services.

Read more
The Measure Of Success: Staying On Track From The Very Beginning

The Measure Of Success: Staying On Track From The Very Beginning

July 6, 2020

Any successful project begins with a clearly defined problem to solve (Are You Solving the Right Problem?). Project stakeholders need to be able to articulate the overriding challenge succinctly from the very start. (Spoiler: this often involves narrowing your vision, and may include…gasp…removing functionality.)

Read more
View more articles