Implementing Dynamic Theming in Android

Nihit Bansal
5 min readMar 22, 2019

--

A short guide for people struggling to implement basic dynamic theming in their Android App.

Example of Dynamic Theming

Hello everyone, today we’ll address an issue that a lot of beginners in the field of android face a lot of trouble in, the Dynamic Theming Problem. It’s often desirable for an app to have multiple themes, whether it be to implement a night mode or even for purely aesthetic reasons. There are a myriad of reasons why you’d wish to change the theme in your app at runtime. So today, I would like to give you an easy method of doing the same.

Let’s get started

Step 1: Create your Project

Get started with making a new Android Studio Project (Note: This guide assumes you want to add themes to a new app you may be creating. In case you already have a project, skip the first 3 steps and modify the subsequent steps as required by you.)

You may choose Add No Activity for now
This guide takes the minimum API level to be 16. You may choose it to be higher depending on your needs

This guide will user Kotlin as the primary language in the Android Studio Project. I’ll see about making another version of this in Java sometime later.

Step 2: Create the Themes for the App

Now we’ll edit the styles.xml file in order to create the two themes to implement in our app. You may choose to make more if you wish for your app to have more customization.

First we’ll add the requisite colors:

Then we’ll use them to create to styles for our Application:

Step 3: Add an Activity

Let us add a sample activity to the app. This activity will be loaded with the default theme (AppTheme.Teal in our case).

package com.example.dynamictheming import android.os.Bundle 
import android.support.v7.app.AppCompatActivity
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}

Now, I’d like to customize our activity a little so that we don’t have to reload an empty looking Activity when we change the theme at the end of the guide.

Here’s what it looks like

Step 4: Create a BaseActivity Class to aid in theme switching

Now it’s time to get started with the actual work of dynamic theming.

We create a new Class called BaseActivity extending AppCompatActivity as shown below.

package com.example.dynamicthemingimport android.os.Build
import android.support.v7.app.AppCompatActivity
abstract class BaseActivity : AppCompatActivity() { companion object {
private const val KEY_THEME = "Theme"
private const val TEAL = R.style.AppTheme_Teal
private const val CYAN = R.style.AppTheme_Cyan
}
}

As you can see, I’ve created a companion object in the class which stores 3 constant variables. These will help us implement the logic of theme switching.

We will use a variable called currentTheme to hold the value of the currently selected theme.

private var currentTheme = TEAL

We not only wish to switch the theme, we wish for it to stay on the selected theme when we restart the app even from a cold open.

For this we store the value of the selected theme in the app’s default Shared Preferences each time it is updated.

We’ll read this value from the Shared Preferences inside the activity’s onCreate() method

override fun onCreate(savedInstanceState: Bundle?) {                                 
currentTheme = PreferenceManager
.getDefaultSharedPreferences(this)
.getInt(KEY_THEME, TEAL)

super.onCreate(savedInstanceState)
}

Now, we add a few methods to the activity:

  1. setTheme(): This method will call the default setTheme(resId: Int) method of the Android Activity by just passing the value of the variable currentTheme into it.
  2. switchTheme(): This method will be used to switch between the two themes and also to store the new value of the theme in the Shared Preferences file.

The final BaseActivity.kt looks like this:

Inherit from this class whenever you want your activity to reflect the dynamic theme of the app.

Step 5: Hookup the Button in MainActivity to switch the themes when clicked

We need to change the MainActivity.kt to inherit from BaseActivity instead of from AppCompatActivity in order to use our newly created theme switching methods.

We’ll also have to call the setTheme() method of the BaseActivity just before setContentView() of the MainActivity is called, otherwise the Activity will fall onto using the default App Style (R.style.AppTheme_Teal in our case).

class MainActivity : BaseActivity() {override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setTheme()
setContentView(R.layout.activity_main)
}

Now, we’ll add an onClickListener to the change theme button in the MainActivity.kt file as shown

changeThemeButton.setOnClickListener { 
switchTheme()
recreate()
}

Make sure you call the recreate() method in the onClickListener. This recreates the activity so that your theme change can actually be reflected.

Here is a Demo of the App in Motion:

Step 6 (Optional): Change the Task Color of the Application in Recents to reflect the current theme of the app

In between Android Version Lollipop (API 21) and Pie (API 28) the Recents Carousel has the following look.

Here, the top bar of the app in this Stack View shows 3 things:

  1. Name of the App
  2. The App Icon
  3. The App’s Primary Color (in the background of the bar)

Till now, our written logic will not change the Primary Color of the app as shown in the recent’s carousel. This view will automatically choose the primary color of the style we define in the AppManifest.xml (R.styles.AppTheme_Teal in our case).

To prevent this from happening, we need to modify something called TaskDescription for the Application whenever we switch the theme.

So let’s get back to BaseActivity.kt and start modifying.

We’ll need to manually set the TaskDescription Property for the app in our switchTheme() method. It takes 3 arguments: The name of the app, the App Icon and the Primary Color.

setTaskDescription(
ActivityManager.TaskDescription(
getString(R.string.app_name),
BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher),
ContextCompat.getColor(this, getColorPrimary())
))

Here, the getColorPrimary() is a helper method I made to return the primary color depending on the currently chosen theme of the app.

Here is what the modified BaseActivity.kt code will look like:

So that’s all folks. This is a basic implementation of Dynamic Theming in Android. You may go ahead and add it into your own apps and projects.

It is easy to implement a Light/Dark Theme using this method too. Just make sure your dark theme extends from a Theme.AppCompat type theme instead of a Theme.AppCompat.Light type theme.

You can find this as a project on Github

Thanks for reading!!

--

--