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:
- create custom attribute
- 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