Table of Contents
Understanding Themes in Android
Themes in Android define the overall look and feel of your app. While styles focus on how individual views look, themes apply a consistent visual configuration to whole activities or even the entire app. A theme controls things like default colors, text appearances, background for screens, and the overall mood of your UI.
A theme is usually applied at the application or activity level, not directly to individual views. When you apply a theme, all views inside that activity will use the theme’s values unless you explicitly override them.
Where Themes Live in Your Project
Themes are defined as resources in XML, usually inside the res/values folder. In modern Android projects you will commonly see:
res/values/themes.xmlfor the light or default theme.res/values-night/themes.xmlfor the night or dark theme version of the same theme.
A basic themes file might look like this:
<resources>
<style name="Theme.MyApp" parent="Theme.Material3.DayNight.NoActionBar">
<item name="colorPrimary">@color/my_primary</item>
<item name="colorOnPrimary">@color/my_on_primary</item>
<item name="android:statusBarColor">@color/my_primary_dark</item>
</style>
</resources>
The name attribute is the theme name. The parent attribute tells Android which existing theme you are extending, often a Material Components theme. Each item line sets a specific attribute inside the theme.
Applying a Theme to Your App or Activity
Themes are connected to your app through AndroidManifest.xml. You specify a theme at the application level or at the activity level.
To apply a default theme to the entire app you use the android:theme attribute on the <application> element:
<application
android:name=".MyApp"
android:theme="@style/Theme.MyApp">
<activity
android:name=".MainActivity" />
</application>
Now all activities will use Theme.MyApp unless you override it for a specific activity.
To give a single activity a different theme you set android:theme on that <activity>:
<activity
android:name=".SettingsActivity"
android:theme="@style/Theme.MyApp.Settings" />
In this case SettingsActivity uses Theme.MyApp.Settings and can look different from the rest of the app, while other activities still use Theme.MyApp.
Always set your app theme in the manifest using android:theme. Changing themes at runtime is possible but more advanced, and should not be your default approach.
Inheriting and Customizing Themes
A theme almost always extends a parent theme. This lets you start from a fully functional base, such as a Material Components theme, and only adjust what you need.
For example, if your app uses Material 3 you might define:
<style name="Theme.MyApp" parent="Theme.Material3.Light.NoActionBar">
<item name="colorPrimary">@color/my_primary</item>
<item name="colorSecondary">@color/my_secondary</item>
</style>You can create a more specific theme that inherits from your main theme:
<style name="Theme.MyApp.Settings" parent="Theme.MyApp">
<item name="android:windowBackground">@color/settings_background</item>
</style>
Here Theme.MyApp.Settings keeps all the behavior and colors from Theme.MyApp but changes the window background. Inheritance lets you reuse most of your design and only specify differences where needed.
Theme Attributes vs Direct Resource References
A theme is a collection of attributes. Some values are concrete resources, like a specific color. Others refer to theme attributes using the ?attr/ syntax.
Inside layouts or styles, you can reference either a hard-coded resource such as @color/my_primary or a theme attribute such as ?attr/colorPrimary.
For example, in a layout:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/colorOnPrimary" />
Here, textColor does not point directly to a color resource. Instead, it asks the currently applied theme for the value of colorOnPrimary. When you switch themes, the same TextView can automatically adapt.
Prefer ?attr/someAttribute when you want your UI to follow the active theme. Use @color/someColor only when you intentionally want a fixed color that will not change with the theme.
Material Components and Theme Requirements
If you use Material Components widgets, such as MaterialButton or TextInputLayout, your theme must extend one of the Material themes. For Material 3 that usually means a parent like:
Theme.Material3.DayNight.NoActionBar
or
Theme.Material3.Light.NoActionBar
Your custom theme then provides the required color and typography attributes. For example:
<style name="Theme.MyApp" parent="Theme.Material3.DayNight.NoActionBar">
<item name="colorPrimary">@color/md_theme_primary</item>
<item name="colorOnPrimary">@color/md_theme_onPrimary</item>
<item name="colorSecondary">@color/md_theme_secondary</item>
<item name="colorOnSecondary">@color/md_theme_onSecondary</item>
</style>If the parent theme is not a Material theme, many Material Components will not display correctly or may crash because expected attributes are missing.
Overriding Specific Theme Attributes
You can fine tune your app by overriding specific attributes in your theme. These attributes control things like the default text appearance, button styling, toolbar color, or status bar color.
For example, to change the color of the status bar you might add:
<style name="Theme.MyApp" parent="Theme.Material3.DayNight.NoActionBar">
<item name="android:statusBarColor">@color/my_status_bar_color</item>
</style>
To define a default style for all Button views in your theme:
<style name="Theme.MyApp" parent="Theme.Material3.DayNight.NoActionBar">
<item name="android:buttonStyle">@style/MyButtonStyle</item>
</style>
Then define MyButtonStyle in your styles or themes file. All Button instances that do not specify their own style will use this theme level default.
Activity and Dialog Theming
Besides regular activities, themes also affect dialogs and some system UI elements. For dialogs, you can either use an existing dialog theme or define a custom one that inherits from it.
A dialog theme might look like:
<style name="Theme.MyApp.Dialog" parent="ThemeOverlay.Material3.Dialog.Alert">
<item name="colorPrimary">@color/my_primary</item>
</style>You then apply this theme when creating a dialog in code or in your layout. Theme overlays, which are mini themes that apply to a part of the screen, are introduced in more detail elsewhere, but they are also represented as styles and are part of the theming system.
Theme Selection Across Android Versions
Android has evolved through several design systems, from Holo to Material to Material 3. Each generation adds new attributes and behaviors. Modern apps usually stick to Material or Material 3. The parent theme you choose should match the libraries you use and the design guidelines you follow.
On older devices, many theme attributes are backported by the AndroidX libraries, especially through AppCompat and Material libraries. This lets you write a single modern theme and still support older Android versions without separate legacy themes.
When you pick a parent theme in a new project template, Android Studio usually provides a ready made Theme.YourApp that already extends a compatible base theme. You then adjust its attributes gradually as you design your app’s look.
Testing and Iterating on Themes
To confirm that your theme works correctly, you should build and run your app and look for unexpected colors, unreadable text, and inconsistent elements. It is useful to try different screens, including dialogs or special activities, to see how the theme behaves everywhere.
You can also temporarily apply a different theme to an activity in the manifest and run just that activity to experiment. Because themes are resource based, you usually do not need to change Kotlin code when adjusting visual aspects. You simply modify the XML in themes.xml, rebuild, and observe the changes.
As your app grows, you will often refine your theme to keep your UI consistent and maintainable, instead of manually styling every single view. A good theme becomes the foundation for a clean and coherent visual design.