You do know Theming Android

Rohan Maity | RotBolt
Coding Blocks
Published in
3 min readMar 10, 2019

This is something I came across when I contributed to Matrix.Org for their Android Client Riot-Android . Issue was simple . On the change of theme proper drawable color was not set. For the reference :

Notice the expand more icon

Ok, so this is about implementing dynamic theming proper way.

BTW you could find the source code here :U Do Know Theming

Basic Setup

Suppose we want dark theme and light theme in our app . First thing is to create styles related to theme

<!-- Light Theme--><style name="AppTheme.Base.Light" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimaryLight</item>
<item name="colorPrimaryDark">@color/colorPrimaryLight</item>
<item name="colorAccent">@color/colorAccentLight</item>
<item name="android:textColor">@android:color/black</item>
<item name="android:textColorSecondary">@android:color/white</item>
<item name="android:itemBackground">@color/colorBackgroundLight</item>
</style>
<!-- DarkTheme--><style name="AppTheme.Base.Dark" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimaryDark</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccentDark</item>
<item name="android:textColor">@android:color/white</item>
<item name="android:textColorSecondary">@android:color/white</item>
<item name="android:itemBackground">@color/colorBackgroundDark</item>
</style>

Now suppose to change the theme on the click of button. So there’s the method

activity.setTheme(int resId)

Woah ! just call this method in setOnClickListener() of button and provide the resource id of your theme (which you could get from R.style.YOUR_THEME_NAME)

And this what I get

😒 😒 😒

Well it turns out

setMethod() should be called before setContentView() in onCreate()

To resolve this, first we can have class ThemeUtils like this

class ThemeUtils {
companion object ThemeUtils {

var sTheme = R.style.AppTheme_Base_Light
fun setTheme(activity: Activity) {
activity.setTheme(sTheme)
}
}
}

sTheme would save our theme to which we want to switch to .

and then for changing theme , first save theme in ThemeUtils and restart the activity

ThemeUtils.sTheme = themeId
startActivity(Intent(this, MainActivity::class.java))
finish()

Then, in the onCreate(), before setContentView() call ThemeUtils.setTheme()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ThemeUtils.setTheme(this)
setContentView(R.layout.activity_main)
....
....
....
}

Finally !!

But wait !! Now we have encountered the same problem like I mentioned in the beginning. Our textColor is changing, but backgroundColor is not setting properly

Solution

One way is to get the current theme and set the backgroundColor of textView as per theme through code

textView.setBackgroundResource(int resId);

But a normal app contains many textViews , drawables etc . Then what ?

Easy, maintainable way

Whenever I used to see google Samples’ code, there was always something like this

android:background="?attr/my_background_color"

Well this attribute referencing .

Like other attributes, we can define our own attributes in attr.xml

Go to res/values -> Right click & new Value resource

<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="my_background_color" format="color"/>
</resources>

Then in our textView background we can give the background as

android:background="?attr/my_background_color"

But how this attribute get its value ??? You just have to give the value of your attribute in different themes (reference it in style)

<!-- Light Theme--><style name="AppTheme.Base.Light" parent="Theme.AppCompat.Light.NoActionBar">.....
.....
<item name="my_background_color">@color/colorBackgroundLight</item>
.....
.....
</style><!-- DarkTheme--><style name="AppTheme.Base.Dark" parent="Theme.AppCompat.Light.NoActionBar">

.....
.....
<item name="my_background_color">@color/colorBackgroundDark</item>.....
.....
</style>

Now after this, my_background_color will get its value from the applied theme or style

Cheers !

If liked then 👏

--

--

Rohan Maity | RotBolt
Coding Blocks

Android lover, Kotlin krazy Anime and other Japanese stuff addict