ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Follow publication

DayNight — Applying dark mode without recreating your app

--

Illustration by Virginia Poltrack

Source is available on Github

How can I avoid recreating my application?

First of all you have to add configChanges mode to activity on your app Manifest file

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:configChanges="uiMode"> //add this line

<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

This line of code will prevent recreating your app when applied dark mode manually or from notification bar, so if you have used colors-night.xml it will be skipped since your app doesn’t recreated. So all coloring stuff now in your hand.

How can I apply colors manually?

In my case I have created colors with “night” ending on my original colors on colors.xml

<color name="colorPrimary">#fff</color>
<color name="colorPrimaryDark">#fff</color>
<color name="colorAccent">#D81B60</color>
<color name="colorText">#1A1A1A</color>


//night mode
<color name="colorPrimaryNight">#000</color>
<color name="colorPrimaryDarkNight">#000</color>
<color name="colorTextNight">#dcdcdc</color>

After altering your colors go to Activity page and override onConfigurationChanged method and apply your colors based on state of nightModeFlags

override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
val nightModeFlags = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK

if (nightModeFlags == Configuration.UI_MODE_NIGHT_NO){
applyDayNight(OnDayNightStateChanged.DAY)
}else{
applyDayNight(OnDayNightStateChanged.NIGHT)
}
}
private fun applyDayNight(state: Int){
if (state == OnDayNightStateChanged.DAY){
//apply day colors for your views
}else{
//apply night colors for your views
}
}

onConfigurationChanged method will be invoked on every DayNight state change, e.g enable or disable Dark Mode from Notification bar or apply manually from code.

I have fragments inside of my Activity, how can I notify them?

Easy, just create interface and extend all fragments where you want apply night mode.

interface OnDayNightStateChanged {

fun onDayNightApplied(state: Int)

companion object{
const val DAY = 1
const val NIGHT = 2
}
}

And extend your fragment with this interface

class YourFragment: Fragment(), OnDayNightStateChanged {

override fun onDayNightApplied(state: Int) {
if(state == OnDayNightStateChanged.DAY){
//apply day colors for your views
}else{
//apply night colors for your views
}
}
}

And you have to notify your Fragments that’s it. For notifying your fragments responsible class is your Activity. On every configuration change your fragments also will get DayNight state.

private fun applyDayNight(state: Int){
if (state == OnDayNightStateChanged.DAY){
//apply day colors for your views
}else{
//apply night colors for your views
}
supportFragmentManager.fragments.forEach {
if(it is OnDayNightStateChanged){
it.onDayNightApplied(state)
}
}
}

Extra: Apply Dark Mode on StatusBar and Navigation Bar

Your status bar and navigation bar have to be also dark with white text and icons on it and vise versa on day state.

If Day mode, then add this on your applyDayNight method in your Activity

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (nightModeFlags == Configuration.UI_MODE_NIGHT_NO) {
decorView.systemUiVisibility = decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
}
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
var flags: Int = decorView.systemUiVisibility
flags = flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR

if (nightModeFlags == Configuration.UI_MODE_NIGHT_NO) {
decorView.systemUiVisibility = flags
}
window.statusBarColor = yourColorDay
}else
window.statusBarColor = yourColorNight

Applying Dark mode

AppCompatDelegate
.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) // night mode
AppCompatDelegate
.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) // day mode
//this will follow system settings (from notification bar)
AppCompatDelegate
.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)

And of course one example

Final result

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Responses (5)

Write a response