Free tutorials & notes in Hindi & English · Clean code examples 🧰 Free PDF & Image Tools →
🎨 UI – Views & Layouts  ·  Lesson 19

Material 3 Theme, Colors & Dark Mode

Theme vs style

Theme

  • Applied to the whole app or an Activity
  • Defines colour roles, fonts, shapes
  • android:theme="@style/Theme.StudentDiary"

Style

  • Applied to one view
  • Groups attributes (size, padding)
  • style="@style/StatNumber"
Both live in res/values/themes.xml

Material 3 colour roles

RoleUsed for
colorPrimary / colorOnPrimaryMain buttons, FAB, active tab · text on them
colorPrimaryContainer / colorOnPrimaryContainerTonal buttons, chips, highlighted cards
colorSecondary / colorTertiaryAccents
colorSurface / colorOnSurfaceScreen and card background · normal text
colorErrorError text and icons
9:41▮▮ 85%Light theme⋮Maths homeworksurface + onSurfacePRIMARY BUTTONContainerChip9:41▮▮ 85%Dark theme⋮Maths homeworksurface (dark)PRIMARY BUTTONContainerChip
Same layout, colours swapped by values-night

The app theme

XML – res/values/colors.xml (Student Diary)
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="brand">#16A34A</color>
    <color name="brand_dark">#15803D</color>
    <color name="brand_light">#DCFCE7</color>
    <color name="accent">#F59E0B</color>
    <color name="star">#F59E0B</color>
    <color name="priority_high">#EF4444</color>
    <color name="priority_medium">#F59E0B</color>
    <color name="priority_low">#22C55E</color>
</resources>
XML – res/values/themes.xml (Student Diary)
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Material 3, light + dark (DayNight). We use our own Toolbar, so NoActionBar. -->
    <style name="Theme.StudentDiary" parent="Theme.Material3.DayNight.NoActionBar">
        <item name="colorPrimary">@color/brand</item>
        <item name="colorOnPrimary">@android:color/white</item>
        <item name="colorPrimaryContainer">@color/brand_light</item>
        <item name="colorOnPrimaryContainer">@color/brand_dark</item>
        <item name="colorSecondary">@color/accent</item>
        <item name="colorOnSecondary">@android:color/black</item>
    </style>

    <style name="StatCard" parent="Widget.Material3.CardView.Filled">
        <item name="cardCornerRadius">16dp</item>
    </style>
    <style name="StatBox">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:orientation">vertical</item>
        <item name="android:gravity">center</item>
        <item name="android:padding">16dp</item>
    </style>
    <style name="StatNumber">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:textSize">28sp</item>
        <item name="android:textStyle">bold</item>
        <item name="android:textColor">?attr/colorPrimary</item>
        <item name="android:text">0</item>
    </style>
    <style name="StatLabel">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:textAppearance">?attr/textAppearanceLabelLarge</item>
    </style>
</resources>

Dark mode with values-night

A file with the same name in values-night/ overrides the theme when dark mode is on.

XML – res/values-night/themes.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Dark mode: lighter green looks better on a dark background -->
    <style name="Theme.StudentDiary" parent="Theme.Material3.DayNight.NoActionBar">
        <item name="colorPrimary">#4ADE80</item>
        <item name="colorOnPrimary">#052E16</item>
        <item name="colorPrimaryContainer">#14532D</item>
        <item name="colorOnPrimaryContainer">#DCFCE7</item>
        <item name="colorSecondary">@color/accent</item>
        <item name="colorOnSecondary">@android:color/black</item>
    </style>
</resources>

Use theme attributes, not fixed colours

XML
<!-- ❌ fixed colour – stays white in dark mode -->
<LinearLayout android:background="#FFFFFF" />

<!-- ✅ theme attributes – change automatically -->
<LinearLayout android:background="?attr/colorSurface" />
<TextView android:textColor="?attr/colorOnSurface" />
<TextView android:textColor="?attr/colorPrimary" />
<TextView android:textAppearance="?attr/textAppearanceTitleMedium" />

Reusable styles

The StatCard, StatBox, StatNumber and StatLabel styles in the theme file above are used three times on the Progress screen — change once, update everywhere.

A dark mode switch

Kotlin – data/SettingsStore.kt
package com.codingeasily.studentdiary.data

import android.content.Context
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.edit

/** Small key-value settings saved with SharedPreferences. */
class SettingsStore(context: Context) {

    private val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)

    var userName: String
        get() = prefs.getString(KEY_NAME, "Student") ?: "Student"
        set(value) = prefs.edit { putString(KEY_NAME, value) }

    var darkMode: Boolean
        get() = prefs.getBoolean(KEY_DARK, false)
        set(value) = prefs.edit { putBoolean(KEY_DARK, value) }

    var remindersEnabled: Boolean
        get() = prefs.getBoolean(KEY_REMINDERS, true)
        set(value) = prefs.edit { putBoolean(KEY_REMINDERS, value) }

    fun applyTheme() {
        AppCompatDelegate.setDefaultNightMode(
            if (darkMode) AppCompatDelegate.MODE_NIGHT_YES else AppCompatDelegate.MODE_NIGHT_NO
        )
    }

    companion object {
        private const val KEY_NAME = "user_name"
        private const val KEY_DARK = "dark_mode"
        private const val KEY_REMINDERS = "reminders"
    }
}
Kotlin – using it
// From Student Diary – SettingsFragment
binding.switchDark.isChecked = settings.darkMode
binding.switchDark.setOnCheckedChangeListener { _, checked ->
    settings.darkMode = checked
    settings.applyTheme()           // the activity is recreated with the new theme
}

// StudentDiaryApp.onCreate() – apply the saved choice when the app starts
SettingsStore(this).applyTheme()
Switch ONSharedPreferencesdark_mode = truesetDefaultNightModeMODE_NIGHT_YESActivity recreatedvalues-night used
How the setting takes effect

Dynamic colour (Android 12+)

Kotlin
// app module: Application class
class StudentDiaryApp : Application() {
    override fun onCreate() {
        super.onCreate()
        DynamicColors.applyToActivitiesIfAvailable(this)   // wallpaper colours on Android 12+
    }
}

Optional: the app picks colours from the user's wallpaper on Android 12+, and uses your colours on older phones.

Common mistakes

  • Hard-coded #FFFFFF backgrounds and #000000 text → unreadable in dark mode.
  • Parent theme from MaterialComponents (M2) mixed with Material3 widget styles → wrong shapes/colours.
  • Forgetting the night version of a custom colour → same bright colour in dark mode.

Summary

  • Theme = whole app (colour roles); style = one view.
  • Theme.Material3.DayNight.NoActionBar + values-night/ = automatic dark mode.
  • Use ?attr/colorSurface, ?attr/colorPrimary etc. in layouts.
  • Save a user choice and call AppCompatDelegate.setDefaultNightMode.
✅ Practice

Generate a scheme in Material Theme Builder with your favourite colour, paste it into your app, and add a three-option dialog: Light / Dark / System.

Frequently Asked Questions

How do I generate a full Material 3 colour scheme?
Use the Material Theme Builder (m3.material.io/theme-builder): pick a seed colour and export Android XML. It creates all colour roles for light and dark themes.
Why does my activity restart when I change dark mode?
AppCompatDelegate.setDefaultNightMode recreates activities so the new resources load. Keep data in a ViewModel so nothing is lost.
Can I follow the phone's dark mode setting?
Yes. Use MODE_NIGHT_FOLLOW_SYSTEM. It is the default when you never call setDefaultNightMode.
← Android Tutorial (Kotlin)
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

Next topicIntents: Open Screens & Apps Your progress: 19 / 43 (44%) · Lesson 20 / 43 Continue →

How was this lesson?

Your feedback helps us make the content better.

Write a review or suggestion (optional)

After approval, your name and city may appear publicly with your review. Please do not write your email or phone number.

▶ CodingEasily on YouTube

Learn with video lessons in easy Hindi

Featured video: RDBMS Part 3 – Class XI Commerce IT

▶ Subscribe – it’s free