Android styles and themes a tutorial
A View
has a set of attributes , such as its android:layout_width
, or its android:layout_height
. Some of these attributes are used to customize the appearance of a view , this is called styling the view , or applying a style to a given view .
This being said , a style can be defined inline , as in the following example :
<?xml version="1.0" encoding="utf-8"?>
<!-- activity_main.xml -->
<LinearLayout ... >
<Button
android:background="@android:color/holo_red_light"
android:textColor="@android:color/white"
android:focusable="false"
android:clickable="false"
...
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button styled" />
</LinearLayout>
Or if maybe it is to create a model , like a button model , which will be applied to multiple button views , it can be defined in a resource file , located in the res/values
folder .
The res/values
folder just contain some files , which contain the definition of some values , such as colors , or strings , or arrays of strings , or dimensions , or styles .
Typically styles are defined in a file named style.xml
, but the file containing style definitions , can be named anything .
The styling resource file , starts with the resources
tag , and contain style
tags , where the style tags contain item
tags , used to define values for some styling attributes . The next example defines a text appearance style , and a button style :
<!--res/values/styles.xml-->
<resources>
<style name="eccentric_appearance_text">
<item name="android:textColor">@android:color/white</item>
<item name="android:textColorHighlight">@android:color/black</item>
<item name="android:textColorHint">@android:color/holo_blue_bright</item>
<item name="android:textSize">22sp</item>
<item name="android:textStyle">italic</item>
</style>
<style name="eccentric_button_style" >
<item name="android:background">@android:color/holo_red_light</item>
<item name="android:focusable">false</item>
<item name="android:clickable">false</item>
<item name="android:gravity">center_vertical|center_horizontal</item>
<item name="android:textAppearance">@style/eccentric_appearance_text</item>
</style>
</resources>
To apply styling to the button , this can be done where the button is defined like so :
<?xml version="1.0" encoding="utf-8"?>
<!-- activity_main.xml -->
<LinearLayout ... >
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/eccentric_button_style"
android:text="Button styled" />
</LinearLayout>
What will happen , is that the view will parse the attributes specified using xml , and apply the specified styling .
A theme has some standard attributes , which it must provide values for , they are defined in the sdk/platforms/android-{version-numer}/data/res/values/attrs.xml
file . For example , for android-30
, an excerpt of the attrs.xml
file , is the following :
<!-- excerpt from sdk/platforms/android-30/data/res/values/attrs.xml -->
<declare-styleable name="Theme">
<!-- ============== -->
<!-- Generic styles -->
<!-- ============== -->
<!-- Specifies that a theme has a light background with dark text on top. -->
<attr name="isLightTheme" format="boolean" />
<!-- Default color of background imagery, ex. full-screen windows. -->
<attr name="colorBackground" format="color" />
<!-- Color used for error states and things that need to be drawn to
the users attention.. -->
<attr name="colorError" format="reference|color" />
<!-- Default background dim amount when a menu, dialog, or something similar pops up. -->
<attr name="backgroundDimAmount" format="float" />
<!-- =========== -->
<!-- Text styles -->
<!-- =========== -->
<!-- Default appearance of text: color, typeface, size, and style. -->
<attr name="textAppearance" format="reference" />
<!-- The most prominent text color. -->
<attr name="textColorPrimary" format="reference|color" />
<!-- Secondary text color. -->
<attr name="textColorSecondary" format="reference|color" />
<!-- Tertiary text color. -->
<attr name="textColorTertiary" format="reference|color" />
<!-- The underline thickness -->
<attr name="textUnderlineThickness" format="reference|dimension" />
<!-- ============= -->
<!-- Button styles -->
<!-- ============= -->
<!-- Normal Button style. -->
<attr name="buttonStyle" format="reference" />
<!-- Small Button style. -->
<attr name="buttonStyleSmall" format="reference" />
<!-- Button style to inset into an EditText. -->
<attr name="buttonStyleInset" format="reference" />
<!-- ToggleButton style. -->
<attr name="buttonStyleToggle" format="reference" />
<!-- ============== -->
<!-- Gallery styles -->
<!-- ============== -->
<!-- The preferred background for gallery items. This should be set
as the background of any Views you provide from the Adapter. -->
<attr name="galleryItemBackground" format="reference" />
<!-- =========== -->
<!-- List styles -->
<!-- =========== -->
<!-- The preferred list item height. -->
<attr name="listPreferredItemHeight" format="dimension" />
<!-- A smaller, sleeker list item height. -->
<attr name="listPreferredItemHeightSmall" format="dimension" />
<!-- The preferred TextAppearance for the primary text of list items. -->
<attr name="textAppearanceListItem" format="reference" />
<!-- The preferred TextAppearance for the secondary text of list items. -->
<attr name="textAppearanceListItemSecondary" format="reference" />
<!-- ============= -->
<!-- Window styles -->
<!-- ============= -->
<attr name="windowBackground" format="reference|color" />
<attr name="windowBackgroundFallback" format="reference|color" />
<!-- ============ -->
<!-- Floating toolbar styles -->
<!-- ============ -->
<attr name="floatingToolbarCloseDrawable" format="reference" />
<attr name="floatingToolbarForegroundColor" format="reference|color" />
<attr name="floatingToolbarItemBackgroundBorderlessDrawable" format="reference" />
<!-- ============ -->
<!-- Alert Dialog styles -->
<!-- ============ -->
<attr name="alertDialogStyle" format="reference" />
<!-- ============== -->
<!-- Image elements -->
<!-- ============== -->
<!-- Icon that should be used to indicate that an app is waiting for a fingerprint scan.
This should be used whenever an app is requesting the user to place a finger on the
fingerprint sensor. It can be combined with other drawables such as colored circles, so
the appearance matches the branding of the app requesting the fingerprint scan.-->
<attr name="fingerprintAuthDrawable" format="reference" />
<!-- ============ -->
<!-- Panel styles -->
<!-- ============ -->
<!-- The background of a panel when it is inset from the left and right edges of the screen. -->
<attr name="panelBackground" format="reference|color" />
<attr name="panelMenuIsCompact" format="boolean" />
<attr name="panelMenuListWidth" format="dimension" />
<attr name="panelMenuListTheme" format="reference" />
<!-- =================== -->
<!-- Other widget styles -->
<!-- =================== -->
<!-- Default Checkbox style. -->
<attr name="checkboxStyle" format="reference" />
<!-- Default EditText style. -->
<attr name="editTextStyle" format="reference" />
<!-- Default Gallery style. -->
<attr name="galleryStyle" format="reference" />
<!-- Default GridView style. -->
<attr name="gridViewStyle" format="reference" />
<!-- Default ListView style. -->
<attr name="listViewStyle" format="reference" />
<!-- Default RadioButton style. -->
<attr name="radioButtonStyle" format="reference" />
<!-- Default Spinner style. -->
<attr name="spinnerStyle" format="reference" />
<!-- NumberPicker style. -->
<attr name="numberPickerStyle" format="reference" />
<!-- The CalendarView style. -->
<attr name="calendarViewStyle" format="reference" />
<!-- =================== -->
<!-- Action bar styles -->
<!-- =================== -->
<!-- Default style for tabs within an action bar. -->
<attr name="actionBarTabStyle" format="reference" />
<!-- Reference to a style for the Action Bar Tab Bar. -->
<attr name="actionBarTabBarStyle" format="reference" />
<!-- Reference to a style for the Action Bar Tab text. -->
<attr name="actionBarTabTextStyle" format="reference" />
<!-- =================== -->
<!-- Action mode styles -->
<!-- =================== -->
<!-- Reference to a style for the Action Mode. -->
<attr name="actionModeStyle" format="reference" />
<!-- Reference to a style for the Action Mode close button. -->
<attr name="actionModeCloseButtonStyle" format="reference" />
<!-- Background drawable to use for action mode UI. -->
<attr name="actionModeBackground" format="reference" />
<!-- =================== -->
<!-- Preference styles -->
<!-- =================== -->
<!-- Default style for PreferenceScreen. -->
<attr name="preferenceScreenStyle" format="reference" />
<!-- Default style for the PreferenceActivity. -->
<attr name="preferenceActivityStyle" format="reference" />
<!-- Default style for Headers pane in PreferenceActivity. -->
<attr name="preferenceFragmentStyle" format="reference" />
<!-- Default style for PreferenceCategory. -->
<attr name="preferenceCategoryStyle" format="reference" />
<!-- Default style for Preference. -->
<attr name="preferenceStyle" format="reference" />
<!-- Default style for informational Preference. -->
<attr name="preferenceInformationStyle" format="reference" />
<!-- Default style for CheckBoxPreference. -->
<attr name="checkBoxPreferenceStyle" format="reference" />
<!-- ============================ -->
<!-- Text selection handle styles -->
<!-- ============================ -->
<!-- Reference to a drawable that will be used to display a text selection
anchor on the left side of a selection region. -->
<attr name="textSelectHandleLeft" format="reference" />
<!-- Reference to a drawable that will be used to display a text selection
anchor on the right side of a selection region. -->
<attr name="textSelectHandleRight" format="reference" />
<!-- Theme to use for dialogs spawned from this theme. -->
<attr name="dialogTheme" format="reference" />
<!-- Window decor layout to use in dialog mode with icons. -->
<attr name="dialogTitleIconsDecorLayout" format="reference" />
<!-- Theme to use for alert dialogs spawned from this theme. -->
<attr name="alertDialogTheme" format="reference" />
<!-- Icon drawable to use for alerts. -->
<attr name="alertDialogIcon" format="reference" />
<!-- Style for button bars. -->
<attr name="buttonBarStyle" format="reference" />
<!-- Style for buttons within button bars. -->
<attr name="buttonBarButtonStyle" format="reference" />
<!-- Background to use for toasts. -->
<attr name="toastFrameBackground" format="reference" />
<!-- Background to use for tooltip popups. -->
<attr name="tooltipFrameBackground" format="reference" />
<!-- Foreground color to use for tooltip popups. -->
<attr name="tooltipForegroundColor" format="reference|color" />
<!-- ============== -->
<!-- Pointer styles -->
<!-- ============== -->
<!-- The drawable for accessibility focused views. -->
<attr name="accessibilityFocusedDrawable" format="reference" />
<!-- ============= -->
<!-- Color palette -->
<!-- ============= -->
<!-- The primary branding color for the app. By default, this is the color applied to the
action bar background. -->
<attr name="colorPrimary" format="color" />
<!-- Dark variant of the primary branding color. By default, this is the color applied to
the status bar (via statusBarColor) and navigation bar (via navigationBarColor). -->
<attr name="colorPrimaryDark" format="color" />
<!-- The secondary branding color for the app. -->
<attr name="colorSecondary" format="color" />
<!-- Bright complement to the primary branding color. By default, this is the color applied
to framework controls (via colorControlActivated). -->
<attr name="colorAccent" format="color" />
<!-- The color applied to framework controls in their normal state. -->
<attr name="colorControlNormal" format="color" />
<!-- The color applied to framework controls in their activated (ex. checked) state. -->
<attr name="colorControlActivated" format="color" />
<!-- The color applied to framework control highlights (ex. ripples, list selectors). -->
<attr name="colorControlHighlight" format="color" />
<!-- The color applied to framework buttons in their normal state. -->
<attr name="colorButtonNormal" format="color" />
<!-- The color applied to framework switch thumbs in their normal state. -->
<attr name="colorSwitchThumbNormal" format="color" />
<!-- The color applied to framework progress and seek bar backgrounds in their normal state. -->
<attr name="colorProgressBackgroundNormal" format="color" />
<!-- The color applied to the edge effect on scrolling containers. -->
<attr name="colorEdgeEffect" format="color" />
<!-- =================== -->
<!-- Lighting properties -->
<!-- =================== -->
<!-- @hide The default Y position of the light used to project view shadows. -->
<attr name="lightY" format="dimension" />
<!-- @hide The default Z position of the light used to project view shadows. -->
<attr name="lightZ" format="dimension" />
<!-- Alpha value of the ambient shadow projected by elevated views, between 0 and 1. -->
<attr name="ambientShadowAlpha" format="float" />
<!-- Alpha value of the spot shadow projected by elevated views, between 0 and 1. -->
<attr name="spotShadowAlpha" format="float" />
</declare-styleable>
As it can be seen from the attrs.xml
file , some attributes are set to have a value , which has a reference format , meaning it must refer to another resource , other attributes are set to must have a literal value , such as a boolean , or a dimension .
An example of a theme , is the holo theme ,which was the default system theme , for application targeting android api , from version 11
inclusive , till version 13
inclusive , and from which an exert is provided :
<!-- excerpt from sdk/platforms/android-30/data/res/values/themes_holo.xml -->
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Holo">
<item name="colorBackground">@color/background_holo_dark</item>
<item name="colorError">@color/error_color_material_dark</item>
<item name="backgroundDimAmount">0.6</item>
<!-- Text styles -->
<item name="textAppearance">@style/TextAppearance.Holo</item>
<item name="textAppearanceInverse">@style/TextAppearance.Holo.Inverse</item>
<item name="textColorPrimary">@color/primary_text_holo_dark</item>
<item name="textColorSecondary">@color/secondary_text_holo_dark</item>
<item name="textColorTertiary">@color/tertiary_text_holo_dark</item>
<!-- Button styles -->
<item name="buttonStyle">@style/Widget.Holo.Button</item>
<item name="buttonStyleSmall">@style/Widget.Holo.Button.Small</item>
<item name="buttonStyleInset">@style/Widget.Holo.Button.Inset</item>
<item name="buttonStyleToggle">@style/Widget.Holo.Button.Toggle</item>
<!-- Gallery attributes -->
<item name="galleryItemBackground">@drawable/gallery_item_background</item>
<!-- List attributes -->
<item name="listPreferredItemHeight">64dip</item>
<item name="listPreferredItemHeightSmall">48dip</item>
<item name="textAppearanceListItem">?attr/textAppearanceLarge</item>
<item name="textAppearanceListItemSecondary">?attr/textAppearanceSmall</item>
<!-- Window attributes -->
<item name="windowNoTitle">false</item>
<item name="windowTitleSize">25dip</item>
<!-- Dialog attributes -->
<item name="dialogTheme">@style/Theme.Holo.Dialog</item>
<item name="dialogCornerRadius">0dp</item>
<!-- AlertDialog attributes -->
<item name="alertDialogStyle">@style/AlertDialog.Holo</item>
<!-- Presentation attributes -->
<item name="presentationTheme">@style/Theme.Holo.Dialog.Presentation</item>
<!-- Toast attributes -->
<item name="toastFrameBackground">@drawable/toast_frame</item>
<!-- Panel attributes -->
<item name="panelBackground">@drawable/menu_hardkey_panel_holo_dark</item>
<item name="panelMenuIsCompact">true</item>
<item name="panelMenuListWidth">250dip</item>
<item name="panelMenuListTheme">@style/Theme.Holo.CompactMenu</item>
<!-- Widget styles -->
<item name="checkboxStyle">@style/Widget.Holo.CompoundButton.CheckBox</item>
<item name="editTextStyle">@style/Widget.Holo.EditText</item>
<item name="galleryStyle">@style/Widget.Holo.Gallery</item>
<item name="gridViewStyle">@style/Widget.Holo.GridView</item>
<item name="listViewStyle">@style/Widget.Holo.ListView</item>
<item name="listViewWhiteStyle">@style/Widget.Holo.ListView.White</item>
<item name="radioButtonStyle">@style/Widget.Holo.CompoundButton.RadioButton</item>
<item name="spinnerStyle">?attr/dropDownSpinnerStyle</item>
<!-- Action bar styles -->
<item name="actionBarTabStyle">@style/Widget.Holo.ActionBar.TabView</item>
<item name="actionBarTabBarStyle">@style/Widget.Holo.ActionBar.TabBar</item>
<item name="actionBarTabTextStyle">@style/Widget.Holo.ActionBar.TabText</item>
<!-- Preference styles -->
<item name="preferenceScreenStyle">@style/Preference.Holo.PreferenceScreen</item>
<item name="preferenceActivityStyle">@style/PreferenceActivity</item>
<item name="preferenceFragmentStyle">@style/PreferenceFragment.Holo</item>
<item name="preferenceCategoryStyle">@style/Preference.Holo.Category</item>
<item name="preferenceStyle">@style/Preference.Holo</item>
<item name="preferenceInformationStyle">@style/Preference.Holo.Information</item>
<item name="checkBoxPreferenceStyle">@style/Preference.Holo.CheckBoxPreference</item>
<!-- Text selection handle attributes -->
<item name="textSelectHandleLeft">@drawable/text_select_handle_left_material</item>
<item name="textSelectHandleRight">@drawable/text_select_handle_right_material</item>
<!-- Scrollbar attributes -->
<item name="scrollbarFadeDuration">250</item>
<item name="scrollbarSize">10dip</item>
<item name="scrollbarThumbHorizontal">@drawable/scrollbar_handle_holo_dark</item>
<item name="scrollbarThumbVertical">@drawable/scrollbar_handle_holo_dark</item>
<!-- Search widget styles -->
<item name="searchWidgetCorpusItemBackground">@color/search_widget_corpus_item_background</item>
<!-- SearchView attributes -->
<item name="searchViewStyle">@style/Widget.Holo.SearchView</item>
<item name="searchDialogTheme">@style/Theme.Holo.SearchBar</item>
<!-- PreferenceFrameLayout attributes -->
<item name="preferenceFrameLayoutStyle">@style/Widget.Holo.PreferenceFrameLayout</item>
<!-- NumberPicker style-->
<item name="numberPickerStyle">@style/Widget.Holo.NumberPicker</item>
<!-- CalendarView style-->
<item name="calendarViewStyle">@style/Widget.Holo.CalendarView</item>
<!-- TimePicker style -->
<item name="timePickerStyle">@style/Widget.Holo.TimePicker</item>
<!-- TimePicker dialog theme -->
<item name="timePickerDialogTheme">?attr/alertDialogTheme</item>
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.Holo.DatePicker</item>
<!-- DatePicker dialog theme -->
<item name="datePickerDialogTheme">?attr/alertDialogTheme</item>
<item name="colorPrimaryDark">@color/holo_primary_dark</item>
<item name="colorPrimary">@color/holo_primary</item>
<item name="colorAccent">@color/holo_blue_dark</item>
<item name="colorEdgeEffect">?attr/colorPrimary</item>
<item name="colorControlNormal">@color/holo_control_normal</item>
<item name="colorControlActivated">@color/holo_control_activated</item>
<item name="colorControlHighlight">@color/holo_button_pressed</item>
<item name="colorButtonNormal">@color/holo_button_normal</item>
<item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item>
<!-- Holo-only color attributes -->
<item name="colorPressedHighlight">@color/holo_gray_light</item>
<item name="colorLongPressedHighlight">@color/holo_gray_bright</item>
<item name="colorFocusedHighlight">@color/holo_blue_dark</item>
<item name="colorMultiSelectHighlight">@color/holo_green_light</item>
<item name="colorActivatedHighlight">@color/holo_blue_dark</item>
</style>
</resources>
So as it can be seen from the provided excerpt , a theme is also defined using the style
tag , in a ressource file inside the res/values
folder . For the holo theme , this file is named themes_holo.xml
.
In a sense , the attributes which a theme defines , have a higher degree of abstraction . So for example , for button styling , the buttonStyleSmall
attribute was specified in the attrs.xml
file , as to be defined , and is defined in themes_holo.xml
, as having the value of@style/Widget.Holo.Button.Small
.@style/Widget.Holo.Button.Small
is defined in sdk/platforms/android-30/data/res/values/res/values/styles_holo.xml
as :
<style name="Widget.Holo.Button.Small">
<item name="background">@drawable/btn_default_holo_dark</item>
<item name="textAppearance">?attr/textAppearanceSmall</item>
<item name="textColor">@color/primary_text_holo_dark</item>
<item name="minHeight">48dip</item>
<item name="minWidth">48dip</item>
</style>
So in other words , different themes can define different values for the buttonStyleSmall
attribute , and as an application developper , if you want to model by using themes , you can specify a style
attribute for a View
, for example the button , by using style="?android:attr/buttonStyleSmall"
, where?android:attr/buttonStyleSmall
means , get the value of the android defined attribute , buttonStyleSmall
, which is set , in the current set theme .
So whatever theme you set for your application , given the fact that you can also change a theme programmatically , or you can not specify a theme , to default to the device default theme , what is being stated is that in all cases , the button must have a styling of button small , so in other words , switching a theme , can switch the style while keeping the intended meaning , and going with the designer conceptions .
Also note that for example , the buttonStyle
, which is defined in a theme , as<item name="buttonStyle">@style/Widget.Holo.Button</item>
, will be applied by default to all buttons , to which the theme is set for , for example in the activity , or in a viewgroup .
A fallback theme , can be specified for all the activities in an application , by using the AndroidManifest.xml
file . A theme can be specified for an activity , for a ViewGroup
such as LinearLayout
, for a specific View
such as a Button
.
<?xml version="1.0" encoding="utf-8"?>
<!-- AndroidManifest.xml -->
<manifest ...>
<application ...
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" >
...
</activity>
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<!-- activity_main.xml -->
<LinearLayout ...
android:theme="@android:style/Theme.DeviceDefault" >
<Button
...
style="?android:attr/buttonStyleSmall" />
<Button
...
style="@android:style/Widget.Holo.Button.Small" />
</LinearLayout>
Applying the theme at a higher level , will make it be inherited at a lower level . So a theme applied to an activity , makes it appliable to its root ViewGroup , if its root ViewGroup , does not specify a theme . The views children of the ViewGroup will also inherit its theme , if they do not specify their own .
In other words , if no theme is specified , higher levels are checked for a theme , if an activity does not specify a theme , the application fallback theme is used , if the application does not specify a theme , then the default theme is used .
The default theme is selected based on the default target sdk version :
If the target sdk is lower than 11
, which is HONEYCOMB
, then the default theme is com.android.internal.R.style.Theme
, which is @android:style/Theme
.
If the target sdk is larger or equal to 11
, and less than 14
, which is ICE_CREAM_SANDWICH
, then the default theme will be com.android.internal.R.style.Theme_Holo
, which is @android:style/Theme.Holo
.
If the target sdk is larger or equal to 14
, and less than 24
, which is android Nougat
, then the default theme will be com.android.internal.R.style.Theme_DeviceDefault
, which is @android/style/Theme.DeviceDefault
. For android platform 30
, this theme has a parent of Theme.DeviceDefaultBase
, which has a parent of Theme.Material
. Theme.DeviceDefault
can be customized by device manufacturor , for example , on older google nexus devices , Theme.DeviceDefault
was actually an alias to the Holo
theme .
If the target sdk is larger or equal to android version 24
, the default theme is com.android.internal.R.style.Theme_DeviceDefault_Light_DarkActionBar
, which is @android:style/Theme.DeviceDefault.Light.DarkActionBar
.
If multiple themes are assigned down the hierarchy , for example if one theme is assigned for the activity , a second one is assigned to the activity root ViewGroup , and a third one , on a View in that ViewGroup , then the most local one applies . Attributes which are defined in a higher level of the hierarchy , but which do not exist in the lower level , are also applied .
So in other words , it is like composing themes together , and this brings us to what is called overlay themes , which might be encountered as in android:theme="@android:style/ThemeOverlay.Material.Light"
. Overlay themes , define a limited set of attributes , as to be composed with other themes .
<!-- sdk/platforms/android-30/data/res/values -->
<!-- Theme overlay that replaces colors with their light versions but preserves
the value of colorAccent, colorPrimary and its variants. -->
<style name="ThemeOverlay.Material.Light">
<item name="colorForeground">@color/foreground_material_light</item>
<item name="colorForegroundInverse">@color/foreground_material_dark</item>
<item name="colorBackground">@color/background_material_light</item>
<item name="colorBackgroundFloating">@color/background_floating_material_light</item>
<item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
<item name="colorError">@color/error_color_material_light</item>
<item name="textColorPrimary">@color/text_color_primary</item>
<item name="textColorPrimaryInverse">@color/primary_text_material_dark</item>
<item name="textColorSecondary">@color/text_color_secondary</item>
<item name="textColorSecondaryInverse">@color/secondary_text_material_dark</item>
<item name="textColorTertiary">@color/secondary_text_material_light</item>
<item name="textColorTertiaryInverse">@color/secondary_text_material_dark</item>
<item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_light</item>
<item name="textColorPrimaryInverseDisableOnly">@color/primary_text_disable_only_material_dark</item>
<item name="textColorHint">@color/hint_foreground_material_light</item>
<item name="textColorHintInverse">@color/hint_foreground_material_dark</item>
<item name="textColorHighlight">@color/highlighted_text_material</item>
<item name="textColorHighlightInverse">@color/highlighted_text_material</item>
<item name="textColorSearchUrl">@color/search_url_text_material_light</item>
<item name="textColorAlertDialogListItem">@color/primary_text_material_light</item>
<item name="textCheckMark">@drawable/indicator_check_mark_light</item>
<item name="textCheckMarkInverse">@drawable/indicator_check_mark_dark</item>
<item name="colorControlNormal">?attr/textColorSecondary</item>
<item name="colorControlHighlight">@color/ripple_material_light</item>
<item name="colorButtonNormal">@color/btn_default_material_light</item>
<item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item>
<item name="colorProgressBackgroundNormal">?attr/colorControlNormal</item>
</style>
The AppCompat support library , which provides backwards compatibility for older android versions , has some themes which are defined , and which start by Theme.AppCompat
, or by ThemeOverlay.AppCompat
, and which can be used as in android:theme="@style/Theme.AppCompat"
or as in style="?attr/buttonStyleSmall"
so without prefixing with android:
, as in to dereference an attribute which belongs or has been defined by the application . If an activity extends an AppCompatActivity
, it must use an AppCompat theme .
Generally in the android platform , or in AppCompat , the themes are either dark themes which use a dark bacground color , with a light foreground such as one used for text , or light themes , and they do , or do not have , an action bar . Light themes can also have a dark action bar .
There is also what is called a DayNight theme , likeTheme.AppCompat.DayNight
orTheme.DeviceDefault.DayNight
. A DayNight theme switches between a dark and a light theme , as instructed to do by using the setDefaultNightMode
method , of AppCompatDelegate
, as follows .
<!-- app/src/main/AndroidManifest.xml -->
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
<application
android:name=".TheApp"
android:theme="@style/Theme.AppCompat.DayNight">
<activity ...
</application>
</manifest>/* src/main/java/com/twiserandom/mobileapps/demo/theme_and_style/TheApp.java */
package com .twiserandom .mobileapps .demo .theme_and_style;
import android .app .Application;
import androidx .appcompat .app .AppCompatDelegate;
public class
TheApp
extends Application {
public void
onCreate ( ){
super .onCreate ( );
AppCompatDelegate .setDefaultNightMode (AppCompatDelegate .MODE_NIGHT_AUTO );
/*
MODE_NIGHT_AUTO_BATTERY :
When battery saver is on , use the dark theme ,
otherwise use the light theme .
MODE_NIGHT_YES :
use the dark theme .
MODE_NIGHT_NO :
use the light theme .
MODE_NIGHT_AUTO , MODE_NIGHT_AUTO_TIME :
use the dark theme , when determined by using
the location or if not possible hardcoded time ,
that it is night . This is deprecated .
MODE_NIGHT_FOLLOW_SYSTEM :
use the system night mode setting ,
to determine if the dark theme is to be used . */ }}
A DayNight theme works by having values for the night category , defined in values-night
, so for exampleTheme.AppCompat.DayNight
has values defined in bothappcompat-version/res/values/values.xml
as<style name="Theme.AppCompat.DayNight" parent="Theme.AppCompat.Light"/>
, andappcompat-version/res/values-night-v8/values-night-v8.xml
as<style name="Theme.AppCompat.DayNight" parent="Theme.AppCompat"/>
, values-night-v8
means this applies starting api version 8
only .
Starting android version 10
, nicknamed Q
, which is api version 29
, it is possible to set the phone theme to a dark theme , by using system settings , hence applications that uses the day and night themes , will automatically switch to the dark theme , unless they have this overriden , as shown earlier .
When an android application is created , it has a default fallback theme , declared in the AndroidManifest.xml
.
<?xml version="1.0" encoding="utf-8"?>
<!-- app/src/main/AndroidManifest.xml -->
<manifest ... >
<application ...
android:theme="@style/AppTheme">
...
</application>
</manifest>
AppTheme is defined in the applicationres/values/styles.xml
, and has the following content :
<!-- app/src/main/res/values/styles.xml -->
<resources>
<!-- Base application theme. -->
<style
name="AppTheme"
parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
So when defining a theme , or a style , a parent can be specified , as seen from the previous example , as not to start from scratch . For a style , it can be done like so :
<!-- app/src/main/res/values/styles.xml -->
<resources>
<style
name="eccentric_appearance_text"
parent="@android:style/TextAppearance.Inverse">
<!--
To inherit from within the android platform
sdk/platforms/android-version/data/res/values/styles.xml ,
the @android:style/What_To_inherit format can
be used .
For example AppTheme can inherit the
Theme.DeviceDefault.Light by using
parent="@android:style/Theme.DeviceDefault.Light"
-->
<item name="android:textColor">@android:color/white</item>
<item name="android:textSize">22sp</item>
<item name="android:textStyle">italic</item>
</style>
<style
name="eccentric_appearance_text.eccentric_button_style"
parent="@style/eccentric_appearance_text" >
<!--
To inherit from within the
application , or within a library in the
application such as AppCompat , the @android:
prefix can be dropped , you can even drop
the @style/ if you want .
So for example eccentric_button_style , can define
a parent of parent="TextAppearance.AppCompat" ,
to specify that its parent style belong to
the AppCompat library .
Also inheritance within the application , not within
libraries that application is using , can be done
using a dot notation in the name , of the like ,
name="eccentric_appearance_text.eccentric_button_style" ,
to specify that eccentric_button_style has a
parent of eccentric_appearance_text .
In such a case it is not necessary to use the
parent attribute , but if the parent attribute
is used , then the styling inherited using
the parent attribute has higher precedence
over styling inherited using the dot notation .
When specifying the style , the complete
dotted name must be used as in
style="@style/eccentric_appearance_text.eccentric_button_style" -->
<item name="android:background">@android:color/holo_red_light</item>
<item name="android:textColor">@android:color/white</item>
<item name="android:focusable">false</item>
<item name="android:clickable">false</item>
<item name="android:gravity">center_vertical|center_horizontal</item>
</style>
</resources>
When applying android:theme
, and style
to a view , the style attributes will have a higher priority than the theme attributes , and inline attributes will have a higher priority than both the theme , and the style attributes , and styling attributes which are set programtically , will have the higher priority .
<?xml version="1.0" encoding="utf-8"?>
<!-- res/layout/activity_main.xml -->
<LinearLayout ... >
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn"
style="@style/eccentric_appearance_text.eccentric_button_style"
android:theme="@android:style/Theme.Holo"
android:textColor="@android:color/holo_green_dark"
android:text="Button styled" />
<!--
Attributes defined in
style="@style/eccentric_appearance_text.eccentric_button_style"
have a higher priority than attributes
defined in android:theme="@android:style/Theme.Holo" ,
but they have a lesser priority than inline
defined attributes of the like of :
android:textColor="@android:color/holo_green_dark" ,
which have a lower priority of styling attributes
set programmatically , as in ,
Button btn = (Button) findViewById(R.id.btn);
btn.setTextColor(Color.BLUE); -->
</LinearLayout>
In newer version of androd studio , the default fallback theme , declared in AndroidManifest.xml
, and which is used to customize an application theming , had a name change , and is now :
<?xml version="1.0" encoding="utf-8"?>
<!-- AndroidManifest.xml -->
<manifest ... >
<application
android:theme="@style/Theme.ThemeAndStyle">
<!--
The application name is actually
Theme And Style , so ThemeAndStyle
is the application name with spaces
being removed . -->
<activity ...
</application>
</manifest>
Theme.[ApplicationName]
is defined inres/values/themes.xml
and res/values-night/themes.xml
. So one is the light theme , and the second one is the dark theme .
<!-- res/values/themes.xml -->
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.ThemeAndStyle" 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>
</resources>
<!-- res/values-night/themes.xml -->
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.ThemeAndStyle" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</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>
</resources>
As seen from the previous excerpt , Theme.[ApplicationName]
has a parent of Theme.MaterialComponents.DayNight.DarkActionBar
which is a new theme by google , defined in a new library called material components , and which can be gotten by adding to the build.gradle
dependencies , the following content :
dependencies {
...
implementation 'com.google.android.material:material:<version>'
// for example , implementation 'com.google.android.material:material:1.1.0'
...
}
The material components library defines , a dark theme Theme.MaterialComponents
, and a light theme Theme.MaterialComponents.Light
, and a day and night theme Theme.MaterialComponents.DayNight
, which all can or cannot have an action bar , as in Theme.MaterialComponents.DayNight.NoActionBar
. Additionally , the day and night theme , and the light theme , can have a dark action bar , as in Theme.MaterialComponents.Light.DarkActionBar
.
The material components library , also defines what is called a bridge theme , this is like , if you were using in an older application , an AppCompat
theme, and you want to switch the theme to the new material component theme , but some constraints forbid you of doing so , then you can use a bridge theme as in Theme.MaterialComponents.Bridge
. Bridge themes inherit from AppCompat
themes , and newer theming must be explicitly enabled , as not to cause attributes errors . For bridge themes , there is a dark and a light version , both with or without an action bar . The light version can also have a dark action bar .
<!-- res/values/themes.xml -->
<resources ...>
<style
name="Theme.ThemeAndStyle"
parent="Theme.MaterialComponents.Bridge">
<item
name="materialButtonStyle">
@style/Widget.MaterialComponents.Button
</item>
<!-- explicitly enabling newer theming .-->
</style>
</resources>
A theme as seen earlier , has a color palette , each application can customize it , as its branding sees fit . To understand how color applies to a theme , google has provided a color tool .
In comparison with the older theming color attributes specified in AppCompat
, or the android api framework used version , the material component library colorPrimary
maps to colorPrimary
, and colorPrimaryVariant
maps to colorPrimaryDark
, and colorSecondary
maps to colorAccent
, and the material component library defines additional coloring attributes .
To customize a theme , it can be done by using xml . In android studio 3.2
, and earlier versions , there was the theme editor tool , but it was removed , starting android 3.3
.
So customizing a theme , is like defining your designer vision , so it is just about defining the values for some models , or attributes , or just creating some totally new attributes . So if the colors are downloaded from the material color tool , and placed in res/values/colors.xml
they will have the following definition :
<?xml version="1.0" encoding="utf-8"?>
<!-- res/values/colors.xml -->
<resources>
...
<color name="primaryColor">#64b5f6</color>
<color name="primaryLightColor">#9be7ff</color>
<color name="primaryDarkColor">#2286c3</color>
<color name="secondaryColor">#b71c1c</color>
<color name="secondaryLightColor">#f05545</color>
<color name="secondaryDarkColor">#7f0000</color>
<color name="primaryTextColor">#000000</color>
<color name="secondaryTextColor">#ffffff</color>
</resources>
And to apply them in the day theme , and to customize it , a little bit further more , this can be done like so :
<!-- /res/values/themes.xml -->
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- define some custom attributes -->
<attr name="MyHeadline6" format="reference"/>
<attr name="MyHeadline7" format="reference"/>
<!-- Define some styles -->
<style
name="MyHeadline6"
parent="TextAppearance.MaterialComponents.Headline6">
<item name="textAllCaps">true</item>
</style>
<style
name="MyHeadline7" >
<item name="fontFamily">sans-serif-thin</item>
<item name="android:fontFamily">sans-serif-thin</item>
<item name="android:textStyle">normal</item>
<item name="android:textAllCaps">false</item>
<item name="android:textSize">14sp</item>
<item name="android:letterSpacing">0.009375</item>
</style>
<style
name="shapeAppearanceSmallComponent"
parent="ShapeAppearance.MaterialComponents.SmallComponent">
<item name="cornerFamily">cut</item>
<item name="cornerSize">24dp</item>
</style>
<style
name="materialButtonStyle"
parent="Widget.MaterialComponents.Button">
<item name="android:textColor">@android:color/holo_orange_dark</item>
</style>
<!-- Define a custom theme -->
<style
name="Theme.ThemeAndStyle"
parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/primaryColor</item>
<item name="colorPrimaryVariant">@color/primaryDarkColor</item>
<item name="colorOnPrimary">@color/primaryTextColor</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/secondaryColor</item>
<item name="colorSecondaryVariant">@color/secondaryDarkColor</item>
<item name="colorOnSecondary">@color/secondaryTextColor</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- custom modeling -->
<item name="MyHeadline7">@style/MyHeadline7</item>
<item name="MyHeadline6">@style/MyHeadline6</item>
<!-- Overriding material button modeling -->
<item name="materialButtonStyle">@style/materialButtonStyle</item>
</style>
</resources>
And if the res/layout/activity_main.xml
has the following content :
<?xml version="1.0" encoding="utf-8"?>
<!-- res/layout/activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<com.google.android.material.button.MaterialButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceHeadline6"
app:shapeAppearance="?attr/shapeAppearanceSmallComponent"
android:text="hello world" />
<com.google.android.material.button.MaterialButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?MyHeadline6"
app:shapeAppearance="@style/shapeAppearanceSmallComponent"
android:text="hello world" />
<com.google.android.material.button.MaterialButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?MyHeadline7"
android:text="hello world" />
<SeekBar
android:id="@+id/seekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<CalendarView
android:id="@+id/calendarView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<SeekBar
android:id="@+id/seekBar2"
style="@style/Widget.AppCompat.SeekBar.Discrete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="10"
android:progress="3" />
<Switch
android:id="@+id/switch1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Switch" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
app:srcCompat="@android:drawable/ic_input_add" />
</LinearLayout>
Then the outcome will be the following :
Finally as stated earlier , a theme can be set programtically , using the settheme
method , as in the following code fragment .
import androidx .appcompat .app .AppCompatActivity;
import android .os .Bundle;
public class
MainActivity
extends AppCompatActivity {
@Override
protected void
onCreate
(Bundle savedInstanceState ){
super .onCreate (savedInstanceState );
setTheme (R .style .Theme_MaterialComponents_NoActionBar_Bridge );
/* setTheme must be called before
any views are instantiated in
the Context , so for example
before setContentView is
called .*/
setContentView (R .layout .activity_main ); } }
Originally published at https://difyel.com on March 22, 2021.