Implementing dark mode has become an essential feature for modern Android applications, offering users a more comfortable viewing experience in low-light environments and potentially conserving battery life. This comprehensive guide delves into how to effectively implement dark mode using DayNight themes in Kotlin with XML layouts for Android development.
Understanding Dark Mode and DayNight Themes
Dark mode is a UI setting that uses a dark color palette for all system UI and supported apps. Android supports dark mode from API level 29 (Android 10) and offers the DayNight theme, a part of the AppCompat library, which simplifies the process of implementing light and dark themes.
Why Implement Dark Mode?
- Enhanced User Experience: Reduces eye strain in low-light conditions.
- Battery Saving: On OLED screens, dark mode can significantly reduce power consumption.
- Accessibility: Improves visibility for users sensitive to bright screens.
Steps to Implement Dark Mode with DayNight Themes
Step 1: Set Up Your Project
Create a new Android project or open an existing one. Ensure your project is using AppCompat, which provides the DayNight theme functionality.
Step 2: Update Dependencies
Ensure you have the necessary dependencies in your build.gradle
file:
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
// Other dependencies
}
Sync your project after adding or updating the dependencies.
Step 3: Configure Themes
Modify your themes.xml
and themes.xml (night)
files to define the light and dark themes, respectively.
res/values/themes.xml
(Light Theme)
<!-- Base application theme. -->
<style name="Base.Theme.DarkModeExample" parent="Theme.Material3.Light.NoActionBar">
<!-- Customize your light theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryVariant">@color/colorPrimaryVariant</item>
<item name="colorOnPrimary">@color/colorOnPrimary</item>
<item name="colorSecondary">@color/colorSecondary</item>
</style>
<style name="Theme.DarkModeExample" parent="Base.Theme.DarkModeExample" />
</resources>
res/values-night/themes.xml
(Dark Theme)
<!-- Base application theme. -->
<style name="Base.Theme.DarkModeExample" parent="Theme.Material3.Dark.NoActionBar">
<!-- Customize your dark theme here. -->
<item name="colorPrimary">@color/colorPrimaryDark</item>
<item name="colorPrimaryVariant">@color/colorPrimaryVariantDark</item>
<item name="colorOnPrimary">@color/colorOnPrimaryDark</item>
<item name="colorSecondary">@color/colorSecondaryDark</item>
</style>
<style name="Theme.DarkModeExample" parent="Base.Theme.DarkModeExample" />
</resources>
Step 4: Define Colors
Define your colors in colors.xml
and colors.xml (night)
for light and dark modes respectively.
res/values/colors.xml
(Light Mode Colors)
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryVariant">#3700B3</color>
<color name="colorOnPrimary">#FFFFFF</color>
<color name="colorSecondary">#03DAC5</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>
res/values-night/colors.xml
(Dark Mode Colors)
<color name="colorPrimaryDark">#BB86FC</color>
<color name="colorPrimaryVariantDark">#3700B3</color>
<color name="colorOnPrimaryDark">#000000</color>
<color name="colorSecondaryDark">#03DAC5</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>
Step 5: Apply Theme in AndroidManifest.xml
Ensure your application uses the defined theme by setting the android:theme
attribute in your AndroidManifest.xml
file.
<application
android:name=".YourApplication"
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/Theme.DarkModeExample">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Step 6: Handle Theme Switching
You can allow users to switch between light and dark themes via a settings option in your app. Use the AppCompatDelegate
to switch themes dynamically.
import androidx.appcompat.app.AppCompatDelegate
fun setDarkMode(isDarkMode: Boolean) {
if (isDarkMode) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
}
}
// Example usage in an Activity or Fragment:
val isDarkModeEnabled = // Retrieve user's preference (e.g., from SharedPreferences)
setDarkMode(isDarkModeEnabled)
To follow the system’s dark mode setting, use:
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
Step 7: Test Your Implementation
Test your implementation thoroughly by manually switching between light and dark modes on your device or emulator. Ensure that all UI elements change appropriately and remain readable.
Advanced Implementation
1. Handling Dynamic UI Elements
For dynamic UI elements (e.g., those created programmatically), ensure you set their colors according to the current theme:
import androidx.core.content.ContextCompat
val textColor = if (isDarkModeEnabled) {
ContextCompat.getColor(context, R.color.textColorDark)
} else {
ContextCompat.getColor(context, R.color.textColorLight)
}
myTextView.setTextColor(textColor)
2. Using Material Components
Material components automatically handle dark mode, but you should ensure you are using the correct theme attributes:
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click Me"
app:backgroundTint="?attr/colorPrimary"
android:textColor="?attr/colorOnPrimary"/>
Conclusion
Implementing dark mode in Android using DayNight themes is a straightforward way to enhance your app’s user experience. By following the steps outlined in this guide, you can create an application that adapts seamlessly to user preferences and system settings, offering both light and dark themes with ease.