Applying multiple themes

Add multi-theme support to your app

Getting started

Before diving further into this guide, you should be familiar with these two procedures:

 

Preparing the theme

After exporting from Figma the new theme, you should have an extra entry available in your theme.xml file. If you have any doubts about how to achieve this, please review the Apply a theme on Android guide again.

 

Switching themes

Next, we need to implement the logic for switching themes. The following are suggestions and should not restrict the implementation and architecture of your application.

 

Create a dynamic theme file in your project

Copy the following code and add it into your application.


                                                        
                                                        
                                                            fun AppCompatActivity.selectedTheme() = themePreferences.getInt(ThemeResIdKey, Int.MAX_VALUE)
                                                        fun AppCompatActivity.setDynamicThemeIfApply() {
                                                            val themeResId = themePreferences.getInt(ThemeResIdKey, Int.MAX_VALUE)
                                                            if (themeResId != Int.MAX_VALUE) setTheme(themeResId)
                                                                observeThemeChanges()
                                                        }
                                                        fun AppCompatActivity.setThemeTo(@StyleRes themeResId: Int) {
                                                            themePreferences.edit(commit = true) { putInt(ThemeResIdKey, themeResId) }
                                                        }
                                                        fun AppCompatActivity.setThemeToDefault() {
                                                            themePreferences.edit(commit = true) { putInt(ThemeResIdKey, Int.MAX_VALUE) }
                                                        }
                                                        private fun AppCompatActivity.observeThemeChanges() {
                                                            lifecycleScope.launch { themePreferences.selectedThemeFlow.collect { recreate() } }
                                                        }
                                                        val AppCompatActivity.themePreferences: SharedPreferences
                                                        get() = getSharedPreferences(ThemePreferencesKey, Context.MODE_PRIVATE)
                                                        private val SharedPreferences.selectedThemeFlow
                                                        get() = callbackFlow {
                                                            val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
                                                                if (ThemeResIdKey == key) trySend(getInt(key, /* defValue = */ Int.MAX_VALUE))
                                                            }
                                                            registerOnSharedPreferenceChangeListener(listener)
                                                            awaitClose { unregisterOnSharedPreferenceChangeListener(listener) }
                                                        }
                                                        private const val ThemePreferencesKey = "theme_preferences"
                                                        private const val ThemeResIdKey = "theme_id"
                                                        
                                                            

 

Update your theme at runtime

At any point you can call the function setThemeTo(resId) and pass the theme resource id as parameter, or in case you want to use the default theme defined in your AndroidManifest.xml file, you can call the function setThemeToDefault().


                                                        
                                                        
                                                            if (selectedTheme() == Int.MAX_VALUE)
                                                            setThemeTo(themeResId = R.style.AppTheme_Premium)
                                                        else setThemeToDefault()