Skip to main content
Flutter Basics – Complete Beginner to Advanced Guide
CHAPTER 15 Beginner

Dark Mode and Theme Customization

Updated: May 16, 2026
6 min read

# CHAPTER 15

Dark Mode and Theme Customization

1. Introduction

Dark mode is no longer a niche feature for power users; it is an industry-standard expectation. Users love dark themes because they save battery life on OLED screens and reduce eye strain in low-light environments. If your app does not support dark mode gracefully, it will feel outdated. In this chapter, we will learn how Android's theme system works, how to implement the DayNight theme, and how to define color resources so your app looks gorgeous in any lighting condition.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand how Android's Resource Qualifier system applies to colors.
  • Use the DayNight Material theme.
  • Create a values-night directory for dark mode colors.
  • Prevent hardcoded colors from breaking your UI.
  • Understand the basics of Material You (Dynamic Color).

3. The DayNight Theme

To support dark mode, your app's base theme must inherit from a DayNight theme. Open res/values/themes.xml. It should look something like this:
xml
1234567
<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight.NoActionBar">
    <!-- Primary brand color. -->
    <item name="colorPrimary">@color/purple_500</item>
    <item name="colorOnPrimary">@color/white</item>
    <!-- Secondary brand color. -->
    <item name="colorSecondary">@color/teal_200</item>
</style>

When using DayNight, Android will automatically switch the default background from white to dark gray, and default text from black to white, based on the user's system settings.

4. Handling Custom Colors (values-night)

While Android handles default backgrounds and text, it doesn't know what to do with your custom colors. If you hardcode a custom background to #EEEEEE (light gray), it will remain bright light gray even in dark mode, blinding the user.

The Solution: Never hardcode colors in your layout XML. Always reference them from colors.xml. Then, create a second colors.xml file specifically for dark mode!

  1. 1. In Android Studio, switch to the "Project" view.
  1. 2. Navigate to res/ and create a new directory called values-night.
  1. 3. Inside it, create a colors.xml file.

Light Mode (res/values/colors.xml)

xml
1234
<resources>
    <color name="card_background">#FFFFFF</color> <!-- White -->
    <color name="brand_text">#333333</color> <!-- Dark Gray -->
</resources>

Dark Mode (res/values-night/colors.xml)

xml
1234
<resources>
    <color name="card_background">#1E1E1E</color> <!-- Dark Surface -->
    <color name="brand_text">#E0E0E0</color> <!-- Light Gray -->
</resources>

Now, in your layout XML:

xml
123
<TextView
    android:textColor="@color/brand_text"
    android:background="@color/card_background" />

The system will automatically pick the correct color file depending on the active theme!

5. Elevation in Dark Mode

In Light Mode, we use drop shadows (Elevation) to show depth. However, shadows are invisible on a dark background! Material Design solves this brilliantly: in Dark Mode, when you increase the elevation of a MaterialCardView, it doesn't just cast a shadow; the surface color actually gets slightly *lighter*. You don't have to code this—the MaterialComponents theme handles it automatically, provided you use the default surface colors.

6. Material You and Dynamic Colors (Android 12+)

Starting in Android 12, Google introduced Material You. Instead of the developer picking the primary colors, the OS extracts a color palette from the user's home screen wallpaper and applies it to the app!

To support this, you apply the Dynamic Colors API in your Application class:

kotlin
123456
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        DynamicColors.applyToActivitiesIfAvailable(this)
    }
}

If dynamic colors are available, the system will override your colorPrimary with the user's chosen wallpaper color, making your app feel deeply personal.

7. Design Principles for Dark Mode

  • Avoid Pure Black: Do not use #000000 for the app background. Use a dark gray like #121212. Dark gray reduces eye strain and allows you to show elevation (a slightly lighter gray card on a dark gray background).
  • Desaturate Colors: Bright, highly saturated colors vibrate visually against dark backgrounds. In your values-night, provide desaturated, pastel versions of your primary colors.

8. Common Mistakes

  • Hardcoding #FFFFFF or #000000: If you write android:textColor="#000000" in your layout, that text will be invisible when the background turns dark. Always use ?attr/colorOnSurface or reference a color resource.
  • Forgetting Vector Icons: If you use a black PNG icon, it will disappear in dark mode. Use Vector Assets and apply app:tint="?attr/colorControlNormal" so they change color automatically.

9. Best Practices

  • Allow the user to override the system setting. Provide a settings toggle in your app: "Light", "Dark", or "System Default".
You can trigger this in code:
kotlin
1
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)

10. Exercises

  1. 1. Create a values-night directory and a colors.xml file inside it.
  1. 2. Define a color named app_background in both the standard and night colors.xml. Use a light gray for day, and a very dark blue for night. Apply it to your main layout and toggle the emulator's dark mode to see it change.

11. UI Design Challenges

Challenge: Ensure an onboarding screen's Hero Image looks good in both modes. Using the -night resource qualifier, create a drawable-night folder. Place a dark-themed version of your illustration there, and the light-themed version in the standard drawable folder with the *exact same filename*. The OS will automatically swap the images!

12. MCQ Quiz with Answers

Question 1

What happens to drop shadows on elevated MaterialCardViews in a dark theme?

Question 2

Which resource directory should you create to hold color values specifically for dark mode?

13. Interview Questions

  • Q: Why is it recommended to use #121212 (dark gray) instead of #000000 (pure black) for dark mode backgrounds?
  • Q: What does the DayNight theme do under the hood?
  • Q: Explain how you would allow a user to manually toggle Dark Mode from within your app's settings.

14. FAQs

Q: Will implementing Dynamic Colors ruin my brand identity? A: It depends. If your app heavily relies on strict brand colors (like a banking app), you might opt out of Dynamic Colors. If your app is a utility or content app, adopting the user's wallpaper colors provides a highly modern, integrated feel.

15. Summary

Supporting Dark Mode is an absolute requirement for modern Android apps. By avoiding hardcoded hex values, utilizing the DayNight theme, and leveraging the values-night resource qualifier, we can create UI designs that adapt beautifully to the user's environment and preferences.

16. Next Chapter Recommendation

Our UI looks beautiful in both light and dark environments, but it still feels a bit static. Static screens are boring. In Chapter 16: Android UI Animations and Transitions, we will breathe life into our app with smooth motion, fade-ins, and layout transitions.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·