Android Material3 toggle dark mode on click

864 Views Asked by At

I want to implement a switch for toggling dark mode in my application. After investigating multiple sources on how to do this correctly, I came across this one-line solution:

AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);

Unfortunately, in my case this only changes the configuration to light mode and doesn't update UI colors. Here's my code:

binding.toggleDarkMode.setOnCheckedChangeListener { _, isChecked ->
   if (isChecked) {
      AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
      activity?.recreate()
   }
}

I'd also like to mention that I have separate theme files for light and dark mode. Light theme extends Theme.Material3.Light.NoActionBar and dark theme extends Theme.Material3.Dark.NoActionBar. Could anyone tell me what could be the problem?

2

There are 2 best solutions below

1
On BEST ANSWER

So basically my phone's OS was overriding my app's styles on a MUI device. Here's the complete answer: Can't disable Night Mode in my application even with values-night

11
On

That line you posted explicitly sets the theme to light mode

AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)

or to put it another way, "not night mode".

If you want it to toggle, you need to get the current mode (light or dark) and set it to the other one:

// check the mode
val isDarkMode = AppCompatDelegate.getDefaultNightMode() == NIGHT_MODE_YES
// set the other
AppCompatDelegate.setDefaultNightMode(if (isDarkMode) NIGHT_MODE_NO else NIGHT_MODE_YES)

or if you're relying on the switch state, just do if (isChecked) instead, no need to get the current mode.


There are more than two modes btw, it's recommended that you handle the "follow the system" one too but that's up to you - more info about the whole thing here from one of the developers.

It also gets into the fact you need to call setDefaultNightMode whenever your app starts, as early as possible, so it can be themed correctly - e.g. in a custom Application class, although if you're doing a single-activity app you could stick it in onCreate there too. Otherwise it would need to go in every Activity, just in case that's the one that's created first when the app is opened/restored.

But what this means is you have to store the light/dark setting so it can be read when the app starts - it doesn't "stick" to the last thing you set it to. You could use SharedPreferences for this, and if your switch is an actual Preference that's all handled automatically! But if it's like a toggle on a normal app screen, you'll have to store it yourself

edit I knew there was something I wanted to mention - you don't need to do activity?.recreate(), setDefaultNightMode will handle that for you if it's required (i.e. if there's been a change)