Android Design System and Theming: Typography.
Note: You can read this post in its github page or in Medium
Managing the look and feel of an Android app can get tedious, and more when the app gets bigger. Style definitions, color attributes, sizes, etc. grow and grow if we don't manage them properly. Even if we can control them, a big set of style definitions can be difficult to follow.
To solve this problem it is recommended, first, to have a Style System (a concrete and small set of styles). And secondly, apply it in your application. For this second part, Android Theming can help us.
Because this topic is large, in this article I will focus just on the typography.
Companion App: You can follow this article with this Github Project: Android Design System and Theming: Typography
Since Android 8.0 fonts can be used as resources. For previous versions, you can use the Support Library 26.
Firstly create the font
folder under the res
folder. Secondly, add your fonts there. Names must be lower case and with underscores. Like other xmls in Android.
Finally, create your font family resources xml file. Here is where the definitions of your fonts will be.
comic_neue.xml
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- You can use `android:` instead of `app:` for API level >= 26 -->
<font
app:font="@font/comic_neue_regular"
app:fontStyle="normal"
app:fontWeight="400" />
<font
app:font="@font/comic_neue_bold"
app:fontStyle="normal"
app:fontWeight="700" />
<font
app:font="@font/comic_neue_light"
app:fontStyle="normal"
app:fontWeight="200" />
<font
app:font="@font/comic_neue_italic"
app:fontStyle="italic"
app:fontWeight="400" />
</font-family>
fontWeight
: Positive number, a multiple of 100, and between 100 and 900, inclusive. The most common values are 400 for regular weight and 700 for bold weight.fontStyle
:normal
oritalic
- Official Documentation
Using in Support Library: Declare font families in XML, using the
app
namespace. Official Documentation
We have everything set up. Now let's use it.
There are 3 ways to do that.
Check the companion project
app
module to see it working. fragment_simple.xml
<TextView
...
android:fontFamily="@font/comic_neue"/>
<style name="MyFontStyle">
...
<item name="fontFamily">@font/comic_neue_bold</item>
</style>
<TextView
...
style="@style/MyFontStyle"/>
Let's see how it can be done.
Android AppCompat library and the Material Design library offer us a set of premade styles that we can use and modify.
Like for example the TextAppearance.AppCompat.Display1
We can use it like any other style
<TextView
style="@style/TextAppearance.AppCompat.Display1"
.../>
In Android Studio right clicking on the style and following the path, we can reach the definition of the style. In this case TextAppearance.AppCompat.Display1
inherits from Base.TextAppearance.AppCompat.Display1
that results in this definition:
<style name="Base.TextAppearance.AppCompat.Display1">
<item name="android:textSize">@dimen/abc_text_size_display_1_material</item>
<item name="android:textColor">?android:textColorSecondary</item>
</style>
in
v21
is actuallyTextAppearance.Material.Headline
but the attributes are very similar.
The same happens with the Material Design Library. For TextAppearance.MaterialComponents.Body1
we can see that it inherits from an appcompat style.
<style name="TextAppearance.MaterialComponents.Body1" parent="TextAppearance.AppCompat.Body2">
This is cool. We can get some premade styles to use in our Design System and tweak them instead of building them from scratch.
The first question would be: Is there a list of all these cool styles?
There are predefined styles for AppCompat and Material Design Libraries.
In the next image, you can see some TextAppearance
styles from the AppCompat Library.
These look big and overwhelming but don't worry we are going to simplify all of it.
To continue, let's check the Material Design documentation for Type Scale about typography.
The main 2 points of its definition are:
- A range of contrasting styles that support the needs of your product and its content.
- A combination of thirteen styles that are supported by the type system. It contains reusable categories of text, each with an intended application and meaning.
TL;DR: They defined 13 styles that should be enough for any application.
Here are the 13 styles:
These styles are used in all the Material Design Definitions. If you go to the Material Design documentation, and look for a component you will find the corresponding Type Scale Category associated with each element.
For example, in the List
component in the theming typography section you can see how they use the Type Scale Category to define the styles of the different list components.
The Android system defines Theme Attributes. Let's see how they differ from the View Attributes.
android:textColor=red
, android:fontFamily="@font/comic_neue"
. <TextView
...
android:fontFamily="@font/comic_neue"/>
colorPrimary = red
, textAppearanceBody1 = ...
. <style name="Base.Theme.MyApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<item name="textAppearanceBody1">@style/TextAppearance.MyApp.Body1</item>
</style>
To use them just set them with the ?attr
keyword first.
<TextView
...
android:textAppearance="?attr/textAppearanceBody1" />
We are talking about typography, so which are the Theme Attributes for typography.
textAppearanceBody1
textAppearanceBody2
textAppearanceButton
textAppearanceCaption
textAppearanceHeadline1
textAppearanceHeadline2
textAppearanceHeadline3
textAppearanceHeadline4
textAppearanceHeadline5
textAppearanceHeadline6
textAppearanceOverline
textAppearanceSubtitle1
textAppearanceSubtitle2
If you remember, the Material Design Docs said: "13 type styles would be enough". Android provides us with these 13 theme attributes.
All these Theme Attributes are set to a specific premade style, and as we did before with the premade styles, we can do it with the theme attributes.
<TextView
...
android:textAppearance="?attr/textAppearanceHeadline5" />
To know which are the default styles that Android uses we just need to follow the path of the theme. Right-click on the attribute, follow the thread until you find the style.
For Theme.MaterialComponents.DayNight.DarkActionBar
you can reach how textAppearanceBody1
is set to the style TextAppearance.MaterialComponents.Body1
<item name="textAppearanceBody1">@style/TextAppearance.MaterialComponents.Body1</item>
You can see that we end up in Base.V14.Theme.MaterialComponents.Light.Bridge
Remember:
res/values/styles.xml
: themes for all versionsres/values-v21/styles.xml
: themes for API level 21+ only
The full list of Typestyles in the Material Design library is this one.
<!-- Type styles -->
<item name="textAppearanceHeadline1">@style/TextAppearance.MaterialComponents.Headline1</item>
<item name="textAppearanceHeadline2">@style/TextAppearance.MaterialComponents.Headline2</item>
<item name="textAppearanceHeadline3">@style/TextAppearance.MaterialComponents.Headline3</item>
<item name="textAppearanceHeadline4">@style/TextAppearance.MaterialComponents.Headline4</item>
<item name="textAppearanceHeadline5">@style/TextAppearance.MaterialComponents.Headline5</item>
<item name="textAppearanceHeadline6">@style/TextAppearance.MaterialComponents.Headline6</item>
<item name="textAppearanceSubtitle1">@style/TextAppearance.MaterialComponents.Subtitle1</item>
<item name="textAppearanceSubtitle2">@style/TextAppearance.MaterialComponents.Subtitle2</item>
<item name="textAppearanceBody1">@style/TextAppearance.MaterialComponents.Body1</item>
<item name="textAppearanceBody2">@style/TextAppearance.MaterialComponents.Body2</item>
<item name="textAppearanceCaption">@style/TextAppearance.MaterialComponents.Caption</item>
<item name="textAppearanceButton">@style/TextAppearance.MaterialComponents.Button</item>
<item name="textAppearanceOverline">@style/TextAppearance.MaterialComponents.Overline</item>
Now we can use the Material theme as a base for our custom Type Styles.
For example, to create our custom style for the Headline5
, we can do as follows.
First, create a file under the res
folder called type.xml
.
Instead of creating the style in the
styles.xml
the new recommendation is the one presented in Developing Themes with Style (Android Dev Summit '19)
Second, add your TextAppearance style.
type.xml
<style name="TextAppearance.MaterialComponents.Headline5.MyApp">
<item name="fontFamily">@font/comic_neue_light</item>
<!-- You can customize other attributes -->
<item name="android:textColor">...</item>
<item name="android:textSize">...</item>
</style>
Easy Hierarchy: Dot notation also applies inheritance so this
TextAppearance.MaterialComponents.Headline5.MyApp
inherits fromTextAppearance.MaterialComponents.Headline5
. You don't need to specify the parent explicitly.
Inheriting from the MaterialComponents
styles will reduce the number of attributes to set and will make your application more consistent with the Material Design Guidelines.
Finally, we need to set up this style to our Theme Attribute in our Theme Definition.
In your themes.xml
add the definition.
<style name="Base.Theme.MyApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<item name="textAppearanceHeadline5">@style/TextAppearance.MaterialComponents.Headline5.MyApp</item>
</style>
Don't forget to add your theme in the manifest.
<application
...
android:theme="@style/Base.Theme.MyApp"/>
And that's it.
In all the TextViews
whose textAppearance
is set to textAppearanceHeadline5
, your custom style will be set.
<TextView
...
android:textAppearance="?attr/textAppearanceHeadline5" />
Another cool feature in the Android Theming System is theme overlays. A Theme Overlay is a technique to change the theme of a part of your view and its descendant in a simple easy way.
In any of your views, you can add the android:theme
attribute and set it to a specific theme. The view and all its children will use the new theme.
ThemeOverlays inherit from an empty parent, should define as few attributes as possible, and its name should start with
ThemeOverlay
, thus it's clear its purpose.
types.xml
<style name="TextAppearance.MaterialComponents.Body1.MyApp.Alternative">
<item name="fontFamily">@font/chakra_petch_bold</item>
<item name="android:textColor">#660099</item>
</style>
styles.xml
<style name="ThemeOverlay.MyApp.TypeScale.Alternative" parent="">
<item name="textAppearanceBody1">@style/TextAppearance.MaterialComponents.Body1.MyApp.Alternative</item>
</style>
fragment_custom.xml
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:text="textAppearanceBody1 of Main Theme"
android:textAppearance="?attr/textAppearanceBody1" /> // Uses the app themes textAppearanceBody1
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.MyApp.TypeScale.Alternative">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:text="textAppearanceBody1 of Theme Alternative1"
android:textAppearance="?attr/textAppearanceBody1" /> // Uses the alternative themes textAppearanceBody1
</LinearLayout>
Check this in the companions app
typescale
module fragment_custom.xml
Some widgets will use the Theme Attributes, so if you have all set you won't need to change anything on the widget, the style will get it properly.
Check this in the companions app
typescale
module fragment_widgets.xml
As you can see in the Companion App in the Widgets Tab, the Button
and the MaterialChip
widgets do not set any textAppearance
in its definition, and it shows the correct Type Style.
But others like the CheckBox
or the Switch
do not have a default textAppearance
. For these (and others) widgets, you would need to set it explicitly.
I would suggest to go with the Material Components Library, the style is more aligned with the Material Documentation.
In case you can't add the library, go with Appcompat but be aware that some theme attributes do not have the corresponding premade style.
Like there is no TextAppearance.AppCompat.Subtitle1
or Headline,2,3,4
but instead Display1,2,3
.
There are 4 steps to have your custom type styles in your Android App using Theming:
<style name="Base.Theme.MyApp" parent="Theme.MaterialComponents.DayNight...
textAppearanceBody1
,textAppearanceHeadline1
...android:textAppearance="?attr/textAppearanceBody1"
Android Styling and Theming is a big topic but once you know how it works it can simplify your style definitions, and increase your development speed.
The Material Design library works pretty well with Android so you can benefit from it. And in case you need to add your custom Design System, it is very easy to create a theme and add your styles.
Many of the topics presented in this article can be applied not only to the typography, but also to colors and shapes. (Let me know if you liked this article and want me to write about colors and shapes).
Before saying goodbye I recommend you checking this Android Dev Summit talk Developing Themes with Style by Nick Butcher and Chris Banes. There are also several posts in Medium by Nick Butcher covering all topics about theming and styling.
Finally, I hope this article helps you to understand Android Theming and Styling a bit better.
Thank you for reading.