Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Activity quickly flashes white before switching to dark / night theme

Tags:

android

kotlin

I've implemented a Dark / night mode switch in my App I copied the implementation from the Google I/O App.

I've created a ThemedActivityDelegate that can be included in ViewModels. The actual changing to light or dark is done using the Extension function: updateForTheme.

But I see the SettingsActivity briefly flashing white before it turns black. While I put the updateForTheme method before setContentView.

MainActivity:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    viewModel = ViewModelProvider(this, viewModelFactory).get(MainViewModel::class.java)
    updateForTheme(viewModel.currentTheme)

    lifecycleScope.launch {
        lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
            launch {
                viewModel.theme.collect { theme ->
                    updateForTheme(theme)
                }
            }
        }
    }
}

Extensions.kt:

fun AppCompatActivity.updateForTheme(theme: Theme) = when (theme) {
    Theme.DARK -> delegate.localNightMode = AppCompatDelegate.MODE_NIGHT_YES
    Theme.LIGHT -> delegate.localNightMode = AppCompatDelegate.MODE_NIGHT_NO
    Theme.SYSTEM -> delegate.localNightMode = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
    Theme.BATTERY_SAVER -> delegate.localNightMode = AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY
}

SettingsActivity:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    updateForTheme(Theme.DARK)
    setContentView(R.layout.activity_settings)
}

UPDATE: When I call updateForTheme(viewModel.currentTheme) before super.onCreate(savedInstanceState) then it works but Dagger isn't initialized then.

like image 475
Jim Clermonts Avatar asked Nov 27 '21 19:11

Jim Clermonts


Video Answer


1 Answers

Try the following:

fun AppCompatActivity.updateForTheme(theme: Theme) {
    val mode = when (theme) {
        Theme.DARK -> AppCompatDelegate.MODE_NIGHT_YES
        Theme.LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
        Theme.SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
        Theme.BATTERY_SAVER -> AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY
        else -> AppCompatDelegate.MODE_NIGHT_UNSPECIFIED
    }
    if (mode != AppCompatDelegate.MODE_NIGHT_UNSPECIFIED) {
        AppCompatDelegate.setDefaultNightMode(mode)
    }
}

Worked well for me in: https://github.com/shlomikatriel/BucksBunny

You may call that setDefaultNightMode on settings while handling user choice.

like image 97
Shlomi Katriel Avatar answered Oct 17 '22 00:10

Shlomi Katriel