Industry updates, technology solutions and company news

Recently I experienced the problem of fake bold and italics using the font family in Android.

I would like to explain this problem and share its solution.
 

Font Family

Since API 26 was released, an ability to combine fonts into font families has appeared.

Font family is a set of fonts with their font styles and weights.

You can create a new font family as an XML resource and access it as a single item, instead of referencing each style and weight as separate resources.
In this way, the system will be able to choose the correct font depending on the text style that you use.

Example of the file:

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
<font
android:fontStyle="normal"
android:fontWeight="400"
android:font="@font/lobster_regular" />
<font
android:fontStyle="italic"
android:fontWeight="400"
android:font="@font/lobster_italic" />
</font-family>



The attribute fontStyle determines individual font style - normal (normal) or cursive (italic).

fontWeight establishes font weight, a/k/a font saturation.

And of course, font sets a font which will be used at the given fontWeight and fontStyle.

                                                                                                                                 

Font Weight
                                   

This standard came from web-development. Value is set from 100 to 900 with a 100 pitch.
                                                                                                                                                     
The table below shows some common names of saturation:

Value

Common name

100

Thin (Hairline)

200

Extra Light (Ultra Light)

300

Light

400

Normal (Regular)

500

Medium

600

Semibold (Demi Bold)

700

Bold

800

Extra Bold (Ultra Bold)

900

Black (Heavy)

950

Extra Black (Ultra Black)



Usually it is enough to specify only fonts for normal glyph (- 400) and standard bold one (- 700) in the font family file.

For details about font saturation, look here.

Fake Italic

                                                                                                                                              When the system can’t find a suitable font for bold or cursive text, Android compensates it by stretching characters for fake bold and by tilting for fake italic.

I created an app which shows the differences between fake styles and the real ones using Lobster Two font as an example:

Using a fake font, you may notice that the text is more flattened. Even worse, this makes it difficult to read because of the smearing of letters and wrong tilt.



Solution

In this example I create lobster_two.xml font family file with fonts for normal, cursive, bold, and bold cursive text:

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
<font
app:fontStyle="normal"
app:fontWeight="400"
app:font="@font/lobster_two_normal" />
<font
app:fontStyle="italic"
app:fontWeight="400"
app:font="@font/lobster_two_italic" />
<font
app:fontStyle="normal"
app:fontWeight="700"
app:font="@font/lobster_two_bold" />
<font
app:fontStyle="italic"
app:fontWeight="700"
app:font="@font/lobster_two_bold_italic" />
</font-family>


I also created lobster_two_incomplete.xml with a font only for normal text:

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
<font
app:fontStyle="normal"
app:fontWeight="400"
app:font="@font/lobster_two_normal" />
</font-family>

And I was switching back and forth between them by pressing the switch.

When lobster_two_incomplete.xml was used instead of lobster_two.xml the font was artificially stretched and tilted.

To prevent this from happening, all sorts of styles in the font family file need to be defined, and this file always must be used as a font.

Using this in the code:

// Correct

val typeFace = resources.getFont(R.font.lobster_two)

textView.setTypeface(typeFace, Typeface.BOLD)

// Incorrect

textView.typeface = resources.getFont(R.font.lobster_two_bold)

// Incorrect

val typeFace = resources.getFont(R.font.lobster_two_incomplete)

textView.setTypeface(typeFace, Typeface.BOLD)

// Incorrect

val typeFace = resources.getFont(R.font.lobster_two_normal)

textView.setTypeface(typeFace, Typeface.BOLD)

Using in xml:

// Correct

<TextView

...

android:fontFamily="@font/lobster_two"

android:textStyle="bold|italic"/>

// Incorrect

<TextView

...

android:fontFamily="@font/lobster_two_bold_italic"/>

// Incorrect

<TextView

...

android:fontFamily="@font/lobster_two_incomplete"

android:textStyle="bold|italic"/>

// Correct

<TextView

...

android:fontFamily="@font/lobster_two"

android:textStyle="bold"/>

// Incorrect

<TextView

...

android:fontFamily="@font/lobster_two_bold"/>

// Incorrect

<TextView

...

android:fontFamily="@font/lobster_two_normal"

android:textStyle="bold"/>


Written by: Veniamin Vynohradov, Android Developer, Zoolatech.