Themes, Styles, and Attributes
Styles and Themes are commonly used for structuring the user interface in Android development. They contain attributes that define the elements’ design. You can create new attributes or reuse the existing ones. You can only assign values to attributes with the types defined in the attribute declaration.
Here’s an example of attribute designation from the Android SDK:
<attr name=”background” format=”reference|color” />
Note: link to another attribute via the “@[package:]type/name” structure is also a type.
Themes vs Styles
Themes and Styles are very similar, but they are used for different purposes.
A Style defines a set of attributes for a single widget. By extracting attributes in styles you can maintain and reuse them easily in a few widgets simultaneously.
A Theme, in turn, defines a set of attributes that can be referenced across the application.
Styles and Themes are intended to work together.
For example, we have a style where the button background is colorPrimary and text color is colorSecondary. The actual values of these colors are defined in the theme.
<?xml version="1.0" encoding="utf-8" ?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="LightTheme" parent="YourAppTheme">
<item name="colorPrimary">#FFFFFF</item>
<item name="colorSecondary">#000000</item>
</style> <style name="DarkTheme" parent="YourAppTheme">
<item name="colorPrimary">#000000</item>
<item name="colorSecondary">#FFFFFF</item>
</style> <style name="Button.Primary" parent="Widget.MaterialComponents.Button">
<item name="android:background">?attr/colorPrimary</item>
<item name="android:textColor">?attr/colorSecondary</item>
</style>
</resources>
When the device switches to the Dark Mode, the app can change its “light” theme to the “dark” one automatically updating the values of the resources.
There is no need to change styles since styles use semantic names rather than specific color resources.
References in XML
The android:background attribute can accept multiple reference types:
android:background=”@color/colorPrimary”
android:background=”?attr/colorPrimary”
In the case with @color/colorPrimary, we refer to color resource colorPrimary or rather to the line which is declared in the res/values/color.xml file:
<color name=”colorPrimary”>#FFFFFF<color>
Note: color is a simple resource that is referenced by the value provided in the “name” attribute but not by the XML file name. Thus, it is possible to combine color resources with the other simple resources in the XML file under one element: <resources>, but I don’t recommend this practice.
On the other hand ?attr is a reference to the theme attribute.
?attr/colorPrimary refers to the colorPrimary attribute in the current theme:
<?xml version="1.0" encoding="utf-8" ?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="YourAppTheme" parent="Theme.AppCompat.Light">
<item name="colorPrimary">@color/colorPrimary</item>
</style>
</resources>
The advantage of the ?attr reference is that it depends on the current theme and will be changed when the theme changes.
Using theme attributes allows you to create fewer styles by isolating changes within the theme.
Always try to refer to color resources through the theme attributes.
Even if you don’t support multiple themes, I would anyway recommend following this approach because it makes further work with themes and styles much easier.
Reference Structure:
@[package:]type/name
- package — (optionally) is the name of the package where the resource resides. By default, this is the application package where the resource is located.
- type — can be one of “color”, “string”, “dimen”, “layout”, etc. Read more here.
- name — is the name of the resource; it is used as a resource identifier.
?[package:]type/name
- package — (optionally) is the name of the package where the resource resides. By default, this is the application package where the resource is located.
- type — (optionally) is always attr when we use ?.
- name — is the name of the resource; it is used as a resource identifier.
? vs ?attr vs ?android:attr
Perhaps, you’ve noticed that you can refer to some attributes by ?android:attr/colorPrimary, ?attr/colorPrimary, and ?colorPrimary as well.
You need to use the android prefix to refer to some attributes because they are only defined in the Android SDK.
We also use ? and ?attr when attributes are defined in the libraries, which are compiled in the application, thus namespace is not needed. (For example, AppCompat and MaterialDesign libraries)
Some elements are defined in both Android SDK and the library such as colorPrimary attribute.
In such cases, it is better to use the attribute from the library since it has support at all API levels.
Useful links
Here is a list of interesting articles about Styles and Themes from the Google Android developers. You may see it below:
- Theming with AppCompat
- Android styling: themes vs styles
- What’s your text’s appearance?
- Android Styling: themes overlay
- Android Styling: prefer theme attributes
- Android styling: common theme attributes
I also recommend watching the Android Dev Summit of 2019. The link to the video.