You do know Theming Android
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 :
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 👏