This is chapter 4 of our Mastering Android themes series. If you have not read Chapter 1, Chapter 2 or Chapter 3. I recommend you to spend 10–15 minutes.

In chapter 3, we agreed on using design langauge and creating custom attributes aligned to design language. We understood theme is equivalent to an object filled with values used by view components at runtime. It is time to master themes.

By now, you must be able to create a good material theme and your designers must be proud of your implementation details. How about jumping to dynamic theme?

Dynamic Theme

Let me ask you a question, try to write the answer and match later. Suppose you are creating a compound viewgroup which plays role of an utility in your project and you have a title bar filled with primaryColor of your theme. How will you do it?

Think. Write and then proceed.

Many developers will write this:

<FrameLayout 
    width, height ... other properties
    android:background="@color/colorPrimary">
</FrameLayout>

If you hardcoded color code, start from chapter 1 again. If you created custom style and applied titleBarStyle with min height and other common properties, bravo!

But we had learnt this topic in last chapter. Aren’t we here to learn dynamic themes? Yes we are! The above solution is correct when you have only one theme, it wont work in multi theme scenario. What could be solution? You can guess, custom attribute.

attr.xml

<attr name="themeColorPrimary" format="reference"/>

Usage

<FrameLayout
    width, height ... other properties
    android:background="?themeColorPrimary">
</FrameLayout>

We defined an attribute themeColorPrimary and we are using it. The attr tag states this attribute is a reference whose value is defined somewhere else. If you use this attr without defining its value, your app will crash. So where do we define it? I guess theme is a good option.

How about our custom theme.

Theme 1 : Indigo

<style name="IndigoTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/indigo</item>
    <item name="colorPrimaryDark">@color/indigoDark</item>
    <item name="colorAccent">@color/indigoLight</item>
    <item name="textColorPrimary">@color/black</item>
    <item name="textColorConnected">@color/green</item>
    <item name="textColorDisConnected">@color/light_gray</item>    
    <item name="themeColorPrimary">@color/indigo</item>
</style>

Theme 2: Pink

<style name="PinkTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/pink</item>
    <item name="colorPrimaryDark">@color/pinkDark</item>
    <item name="colorAccent">@color/pinkLight</item>
    <item name="textColorPrimary">@color/black</item>
    <item name="textColorConnected">@color/green</item>
    <item name="textColorDisConnected">@color/light_gray</item>    
    <item name="themeColorPrimary">@color/pink</item>
</style>

Now you can simply apply these themes dynamically:

setTheme(R.style.PinkTheme);

OR

setTheme(IndigoTheme);


Tip: You need to call recreate() method in activity to ensure activity recreates itself and lifecycle is called again, so you can inflate your xml with new theme in onCreate() method.

Wasn’t that simple? However I see a small problem there. Rule number 1 of programming, duplicacy is bad! It leads to future maintenance issues and we just left duplicacy in above themes. colorPrimary and **themeColorPrimary **both are assigned same value. Being master, we can not tolerate such flaws. How about this?

Theme 1 : Indigo

<style name="IndigoTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">?themeColorPrimary</item>
    ...
     ....
    <item name="themeColorPrimary">@color/indigo</item>
</style>

Theme 2: Pink

<style name="PinkTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">?themeColorPrimary</item>
    ...
     ....
    <item name="themeColorPrimary">@color/pink</item>
</style>

Woo! Now colorPrimary is referring to our custom atribute. Thats awesome!

Do you still see scope of improvement here? Write down your answer before reading further.

And the answer is


Yes, I do. We just cleaned our xml little bit and removed duplicacy but I still smell duplicacy which can be avoided easily. I see

<item name="colorPrimary">?themeColorPrimary</item>

at two places(in both themes). Why not make it even better!

How about this?

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">?themeColorPrimary</item>
</style>

Theme 1 : Indigo

<style name="ThemeIndigo" parent="AppTheme>
    <item name="themeColorPrimary">@color/indigo</item>
</style>

Theme 2 : Pink

<style name="ThemePink" parent="AppTheme>
    <item name="themeColorPrimary">@color/pink</item>
</style>

We just created a parent themes and extended two themes from it. We understand real user of Inhertitance. We truly are a master.

Note: You could also extend style with dot operator. Example:

<style name="AppTheme.ThemeIndigo">
    <item name="themeColorPrimary">@color/indigo</item>
</style>

It is same as mentioning parent explicitly.

Needless to say, you should be able to create awesome themes by now. Both static and dynamic. Cheers!

We have come a long way. I bow to you, Master.

Summary of all chapters

Git Repo for Dynamic Theme Sample

Subscribe to newsletter and keep learning good stuff

Email

👉 If you like article, click on ♥️ recommend and share on social 👥 media.
👉 Feel free to comment 💬
👉 Follow me 👀 for the more interesting articles. Twitter Medium
👉 Subscribe to newsletter and keep learning