Styles and themes

An attribute is a key-value pair that can specify the appearance of app, activity, or view. For example, font color, font size, background color, and etc.

A style is a collection of attributes that specify the appearance for a single View.

A style reference can also be used as an attribute value.

A theme is a collection of attributes that's applied to an entire app, activity, or view hierarchy—not just an individual view. There are two useful themes:

  • Theme.AppCompat - from androidx library
  • Theme.MaterialComponents - material theme from Google

To use material theme you need add google repository to gradle and dependency (more details )

implementation 'com.google.android.material:material:1.5.0'

Both themes have variations like night mode.

attributes

R.attr contains all attributes provided by Android.

R.styleable contains all attributes of a specific view or window that can be defined in a style.

Custom attributes usually are defined in /res/values/attrs.xml file.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="headerColor" format="reference|color" />
    
    <declare-styleable name="CustomImageView">
        <attr name="borderWidth" format="dimension" />
        <attr name="borderColor" format="color" />
    </declare-styleable>
</resources>

Details of using the styleable attributes read in the article how to create custom views.

styles

R.style class defines default styles and themes. To use the styles listed here, replace all underscores in the style name with a dot. Also you can see a style source file

<!-- Theme_NoTitleBar > @android:style/Theme.NoTitleBar -->
<application android:theme="@android:style/Theme.NoTitleBar" ... >

Typically, custom styles and themes are declared in the res/values/styles.xml file.

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">    
    <style name="app_bt_action_style">
        <item name="android:layout_width">@dimen/ap_card_bt_action_size</item>
        <item name="android:layout_height">@dimen/ap_card_bt_action_size</item>
        <item name="android:padding">@dimen/paddingSmall</item>
    </style>
</resources> 

<!--
Then you can apply style to the view in the layout file
<androidx.appcompat.widget.AppCompatImageView
    android:id="@id/fiActionShowOriginal"
    style="@style/app_bt_action_style" />
-->

You can extend and customize the style by overriding the attribute values. Parent style can be specified via referrence or dot notation.

<style name="GreenText1" parent="@android:style/TextAppearance">
    <item name="android:textColor">#00FF00</item>
</style>
<style name="GreenText2" parent="TextAppearance.AppCompat">
    <item name="android:textColor">#00FF00</item>
</style>

You can extend your own styles with dot notation without specifying a parent style.

<style name="GreenText1.Large">
    <item name="android:textSize">22dp</item>
</style>

You can assign style to the view at the creation time.

// API 21+
val txtView = TextView(ContextThemeWrapper(this, R.style.mystyle))

val txtView2 TextView(this, null, 0, R.style.mystyle)

themes

R.style class defines default styles and themes. To use the themes listed here, replace all underscores in the theme name with a dot. Also you can see a theme source file.

Like styles you can extend and customize the themes by overriding the attribute values.

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <!-- Primary brand color. -->
        <item name="colorPrimary">@color/purple_500</item>
        <item name="colorPrimaryVariant">@color/purple_700</item>
        <item name="colorOnPrimary">@color/white</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_700</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
    </style>

    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>
</resources>

You can assign theme in the Manifest.xml file in the application or activity element. By default theme of app is used for all activities.

<application 
    ...
    android:theme="@style/MyAppTheme">
    
    <activity android:theme="@style/MySpecialActivtyTheme"
        ...
    >

multiple themes

You can programmatically assign theme on the activity creation stage by the setTheme() method. You should call it before calling the setContentView() and super.onCreate() methods inside the onCreate().

To change the theme dynamically, you need to recreate the current activity with a different theme. Additionally, you can customize activity transitions with fading animations.

 override fun onCreate(savedInstanceState: Bundle?) {
    val idTheme = getThemeIdFromSomewhere()
    setTheme(if(idTheme!=0) idTheme else android.R.style.Theme_Dark)
    
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_activity)
    // ...
}    

override fun recreate() {
    finish()
    
    overridePendingTransition(
        R.anim.anime_fade_in,
        R.anim.anime_fade_out
    )
    
    startActivity(intent)
    
    overridePendingTransition(
        R.anim.anime_fade_in,
        R.anim.anime_fade_out
    )
}

current theme

An attribute value in style or theme can referrs to the the value of an attribute in the currently-applied theme. It allows to customize the look of UI elements to match standard variations supplied by the current theme, instead of supplying a hard-coded value.

?[<package_name>:][<resource_type>/]<resource_name>
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
       name="colorPrimaryVariant">@color/purple_700</item>
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
        <!-- ... -->
    </style>

    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>
</resources>

<!-- some view style -->
<style name="GreenText2" parent="TextAppearance.AppCompat">
    <item name="android:textColor">?attr/colorPrimary</item>
</style>

Also you can reffer to the theme attribute from layout file.

<EditText id="text"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textColor="?android:textColorSecondary"
    android:text="@string/hello_world" />

theme colors

Different parts of the UI use different colors. Material design defines twelve colors for theme.

You can generate own palette with the material palette generator.

attribute name description
colorPrimary Primary colors map to components and elements, like app bars and buttons.
colorPrimaryVariant
colorSecondary Secondary colors are most often used as accents on components, such as FABS and selection controls.
colorSecondaryVariant
colorBackground Background color is found behind scrollable content.
colorSurface Surface colors map to components such as cards, sheets, and menus.
colorError Error color indicates errors in components, such as text fields.
colorOnPrimary
colorOnSecondary
colorOnBackground
colorOnError

Color variants can be used to complement and provide accessible options for your primary and secondary colors.

“On” colors are primarily applied to text, iconography, and strokes. Sometimes, they are also applied to surfaces.

Why we need “On” colors? The elements in an app use colors from specific categories in your color palette, such as a primary color. Whenever other screen elements, such as text or icons, appear in front of surfaces using those colors, those elements should use colors specifically designed to appear clearly and legibly against the colors behind them.

There are additional handy colors.

attribute name description
colorControlNormal The color applied to icons/controls in their normal state.
colorControlActivated The color applied to icons/controls in their activated state (e.g. checked).
colorControlHighlight The color applied to control highlights (e.g. ripples, list selectors).
textColorPrimary This is the default text color for enabled buttons textviews with large appearance.
textColorSecondary This is the default text color for textviews with medium and small appearance.
 <TextView
        ... 
        android:textColor="?android:textColorSecondary"/>

text appearance

TextAppearance class contains data for styling the TextView's text-related attributes such as text color and size. It does not include view-related attributes like the top drawable.

Material design defines 13 text styles that you can use in theme.

?attr/textAppearanceSubtitle1 defaults to regular 16sp text. ?attr/textAppearanceSubtitle2 defaults to medium 14sp text.
attribute name description
textAppearanceHeadline1 By default it is a light 96sp text.
textAppearanceHeadline2 By default it is a light 60sp text.
textAppearanceHeadline3 By default it is a regular 48sp text.
textAppearanceHeadline4 By default it is a regular 34sp text.
textAppearanceHeadline5 By default it is a regular 24sp text.
textAppearanceHeadline6 By default it is a medium 20sp text.
textAppearanceSubtitle1 By default it is a regular 16sp text.
textAppearanceSubtitle2 By default it is a medium 14sp text.
textAppearanceBody1 By default it is a regular 16sp text.
textAppearanceBody2 By default it is a regular 14sp text.
textAppearanceCaption By default it is a regular 12sp text.
textAppearanceButton By default it is a medium all caps 14sp text.
textAppearanceOverline By default it is a medium all caps 10sp text.

There are additional handy text styles.

attribute name description
textAppearanceLarge Represents large text.
textAppearanceMedium Represents medium text.
textAppearanceSmall Represents small text.

In the layout file, you can assign the textAppearance attribute to an attribute or style reference.

<TextView
    ...
    android:textAppearance="?android:attr/textAppearanceSmall" />

<TextView
    ...
    android:textAppearance="?attr/textAppearanceHeadline5" />

<TextView
    ...
    android:textAppearance="@style/TextAppearance.AppCompat.Medium"
    />

Also you can assign text appearance programmatically.

TextViewCompat.setTextAppearance(textView, android.R.style.TextAppearance_Large)
TextViewCompat.setTextAppearance(textView, R.style.TextAppearance_AppCompat_Large)

textView.setTextAppearance(R.style.TextAppearance_AppCompat_Large);

theme example

To create new theme with custom attributes you need:

  1. create custom attribute
  2. specify value of attribute in one or more themes

1. Add new attribute

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="headerColor" format="reference|color" />
</resources>

2. Define two theme with the our attribute

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="AppThemeRed" parent="@style/Theme.AppCompat.Light.DarkActionBar">
    <item name="android:textColor">@color/white</item>
    <item name="headerColor">@color/red</item>
</style>
<style name="AppThemeGray" parent="@style/Theme.AppCompat.Light.DarkActionBar">
    <item name="android:textColor">@color/white</item>
    <item name="headerColor">@color/gray</item>
</style>

3. Define style that uses our attribute.

<style name="Header" parent="@android:style/TextAppearance.Medium">
    <item name="android:textColor">?headerColor</item>
</style>

Read more, how to define a color resource.

variations of material theme

  • Theme.MaterialComponents
  • Theme.MaterialComponents.NoActionBar
  • Theme.MaterialComponents.Light
  • Theme.MaterialComponents.Light.NoActionBar
  • Theme.MaterialComponents.Light.DarkActionBar
  • Theme.MaterialComponents.DayNight
  • Theme.MaterialComponents.DayNight.NoActionBar
  • Theme.MaterialComponents.DayNight.DarkActionBar