Custom and Downloadable Fonts on Android

Ivan Kust
Custom fonts

Make awsome quizzes with custom fonts!

Since the beginning of Android, there was no out of the box solution for using custom fonts. Only a small set of preinstalled fonts on the device was available.

You had to be creative and write a lot of code for such a trivial thing.

Recently, Google introduced Custom and Downloadable fonts for Android 8.0. They’ve also provided support for earlier Android versions through Support Library version 26.

In this tutorial, you’ll get to know how to use them by creating a simple quiz app. In the process, you’ll learn:

  • How to add custom fonts in your app
  • How to define font families
  • How to add downloadable fonts from a provider
  • How to retrieve font information

Let there be fonts! :]

Note: This tutorial assumes you know the basics of Android development with Kotlin. If you are new to Kotlin check out our Kotlin introduction tutorial. If you are new to Android development, check out our Android Tutorials first.

History: Difficulties in the Past

Up until recently, to use a custom font on a View, you had to do several things:

  1. Put your font files in the assets folder
  2. Load the font from the asset file into a Typeface object
  3. Set that Typeface to your view using setTypeface()

The main disadvantage in this approach was that you couldn’t set the font in layout files – you had to do it in code:

val myTypeface = Typeface.createFromAsset(assets, "fonts/myFont.ttf")
myTextView.typeface = myTypeface

To remedy that you could extend your view classes and add a custom attribute for passing the font file from layout. That was a little bit better but there were still issues:

  • You had to extend every type of View you wanted to apply a custom font to
  • On some devices loading from assets could take a long time so you had to cache fonts in memory
  • In some cases things could get messy – for example if you had to change the font on Toolbar

Not to mention that it felt wrong extending a TextView just for setting a custom font.

Getting Started

Requirements

To work with custom fonts you’ll first have to install the latest Android Studio 3.x. This is important as some of the features are not supported on Android Studio 2.x – for example the font resource directory.

Install Android Studio by following the instructions in our Beginning Android development tutorial.

Your first task will be to switch to the latest support library. You can download the starter project here.

Open up Android Studio and import the starter project with File\Open. Select the location where you extracted the starter project and click Open on the dialog.

Once the project is open and synced, build and run the project.

You have a simple font quiz app. If you start the quiz you’ll get a series of 5 questions which ask you to guess the font of the text.

But wait – the text is always in the same (default) font! We’ll get to that shortly. First let’s add the latest support library.

Add the latest support library

Open build.gradle file in \app folder (in the Android project view you can find it under Gradle Scripts) and update the support library line in the dependencies { … } section:


implementation 'com.android.support:support-v4:27.0.2'


This will add the latest version of the Android support library that ports Custom and Downloadable fonts back to Android from API versions 14 up.

You also need to change your compileSdkVersion and targetSdkVersion to 27. Finally, change the other support library dependencies (i.e., appcompat and design) to version 27.0.2.

Once done, click Sync now on the gradle notification on top of editor window.

After gradle has synced up, build and run the app again to make sure everything is still working:

There is no visible change for now, but hold tight – we are ready to add some custom fonts!

Bundled fonts

Google introduced a new feature with Android 8 – font resources. Put font files into the res\font folder to bundle them in the .apk as resources. These fonts compile in the R file and are available in Android Studio the same way as string, drawable and color resources.

Note: Using font resources is possible in Android Studio 3.x and not in Android Studio 2.x.

The next thing you will do is add a custom .ttf font to the app. Download the OpenSans-regular font here.

Go back to Android Studio and make sure you select Android in Project navigator:

Click on the res folder, press ⌘N (or File\New) and select Directory.

A dialog to enter a new directory name will pop up. Name it font:

Now, right click on the new directory and click Reveal in Finder (macOS), Reveal in Explorer (Windows), or Show in Files (Linux). Move the downloaded OpenSans-Regular.ttf file to the fonts folder you’ve opened and rename it to opensans_regular.ttf. Only alphanumeric characters and underscore are valid in an android resource name.

Go back to Android Studio and open the res\layout\activity_main.xml file. Find AppCompatTextView with the id tvFontQuiz. Add the following property to it:

app:fontFamily="@font/opensans_regular"

The layout code for the text view should look like this now:


<android.support.v7.widget.AppCompatTextView
  android:id="@+id/tvMessage"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@string/quiz_message"
  android:textAlignment="center"
  app:fontFamily="@font/opensans_regular"
  app:layout_constraintBottom_toTopOf="@+id/startButton"
  app:layout_constraintLeft_toLeftOf="parent"
  app:layout_constraintRight_toRightOf="parent"
  app:layout_constraintTop_toTopOf="parent" />

Build and run your project.

You can see that the message is now in OpenSans font. Easy peasy!

Creating a font family

Another new capability is that you can create font families which contain a set of font files along with their style and weight details. To create a new font family you will actually create a new XML font resource. The benefit is that you can access it as a single unit instead of referencing individual font files for each style and weight as a separate resource.

You’ll now create a new font family. First, let’s get the bold version of OpenSans.

Repeat the same procedure from the last step and add new font file to the font folder of the project. Rename the file to opensans_bold.ttf.

The next thing you’ll do is create a font family resource.

Click on the res\font folder, press ⌘N (or File\New) and select Font resource file.

Type opensans under File name and click Ok.

Android studio will generate an empty font family resource:


<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">

</font-family>

Add two font files to the font family by using the <font> element. It has three attributes:

  • font: font file resource identifier
  • fontStyle: style to which the font file corresponds, can be normal or italic
  • fontWeight: text weight to use for the font

To add regular and italic font resource you’ll add two <font> elements:

<?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/opensans_regular" />
  <font
      android:fontStyle="italic"
      android:fontWeight="400"
      android:font="@font/opensans_bold" />
</font-family>

Note that to be backwards compatible to Android versions older than 8.0 you have to declare all font properties in the app namespace as well. This will use the custom font implementation from the support library. After adding them your resource file should look like this:

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

Now go back to res/layout/activity_main.xml and change the app:fontFamily property on tvMessage to opensans:

<android.support.v7.widget.AppCompatTextView
  android:id="@+id/tvMessage"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@string/quiz_message"
  android:textAlignment="center"
  app:fontFamily="@font/opensans"
  app:layout_constraintBottom_toTopOf="@+id/startButton"
  app:layout_constraintLeft_toLeftOf="parent"
  app:layout_constraintRight_toRightOf="parent"
  app:layout_constraintTop_toTopOf="parent" />

Build and run your project.

Custom fonts in layouts

You’ve already seen in previous steps how to add a custom font to TextView. Now you will add a custom font to a Theme, changing the default font on all Activities that use the Theme.

Open the file res/values/styles.xml.

Change app theme Theme.FontQuiz – add the fontFamily attribute:

<style name="Theme.FontQuiz" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="fontFamily">@font/opensans</item>
</style>

Build and run the app.

You can see that across the app, OpenSans is now used:

Custom fonts programatically

You can set the custom font programatically as well. To do that you will use the ResourcesCompat class from the support library. Type the following at the end of the onCreate() method in MainActivity:

val typeface = ResourcesCompat.getFont(this, R.font.opensans_bold)
startButton.typeface = typeface

Build and run your project.

You can see that the font on the start button has been set to OpenSans Bold.

Note again that you use the support library to support Android versions earlier than Android 8.0.

Downloadable fonts

Now that you’ve seen how custom fonts work, let’s jump onto another novelty – downloadable fonts. Downloadable fonts allow you to add fonts to your application that download on demand or when your application starts.

This has more benefits:

  • fonts get downloaded only when required
  • reduced application .apk size
  • more applications can share fonts through font providers which can reduce used disk space

How Font Providers work

Font providers take care of retrieving and caching downloadable fonts used across applications. This is what the process of requesting a font looks like:

All applications that use downloadable fonts pass their requests via FontsContractCompat. It then communicates with the requested font provider. A font provider is an application that takes care of fetching and caching the appropriate fonts. There can be more of them installed on a device but currently only a Google font provider is available.

Security & certificates

To ensure security when using font providers, you have to provide the certificate used to sign by the font provider. This enables Android to verify the identity of the font provider. You have to do this for font providers that are not pre-installed on the device or when using support library.

Your next task is to add the certificate for the Google font provider.

Click on the res\values folder, press ⌘N (or File\New) and select Values resource file.

In the dialog, name it font_certs and click Ok.

You define font provider certificates in a string-array. If the font provider has more than one set of certificates, then you must define an array of string arrays. The Google font provider used with the support library uses two sets of certificates, and the next step is to define an array for each set.

Add a string array in the new file by adding <string-array> in the <resources> section and name it com_google_android_gms_fonts_certs_dev.

Add a single item to it with the following content:

<item>
MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
</item>

Now add another string array with the name com_google_android_gms_fonts_certs_prod and add a single item to it with the following content:



<item>
MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
</item>

Finally, create an array named com_google_android_gms_fonts_certs and add the two previously defined string arrays as its items.

Your font_certs.xml file should now look like this:


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <array name="com_google_android_gms_fonts_certs">
        <item>@array/com_google_android_gms_fonts_certs_dev</item>
        <item>@array/com_google_android_gms_fonts_certs_prod</item>
    </array>
    <string-array name="com_google_android_gms_fonts_certs_dev">
        <item>
            MIIEqDCCA5CgAwIBA…
        </item>
    </string-array>
    <string-array name="com_google_android_gms_fonts_certs_prod">
        <item>
            MIIEQzCCAyugAwIBAgIJAMLgh0…
        </item>
    </string-array>
</resources>

Build and run your project.

There is no visible change but you are now ready to add downloadable fonts.

Downloadable fonts programatically

The FontQuiz application is still missing one key feature – text in quiz questions always must be in font from the question.

You can implement requests to fetch downloadable fonts and apply them to a View in code as well. You must use the FontsContractCompat class from the support library to support Android versions older than 8.0.

Your task will be to use it to request and set a random font on the quiz question Activity.

Open QuestionActivity and find the showFont() method.

Font family names available for the quiz are in a list in res\values\family_names.xml file. The logic to pick a random font for the question and four offered answers is already there. Your job is to request and show the font with the name passed to showFont().

First, hide all the buttons and show a ProgressView that will show hat font is loading by adding:

buttons.forEach { button -> button.isEnabled = false }
progressView.visibility = View.VISIBLE

Build and run your project.

Click on “Start Quiz” and you’ll see disabled buttons and a progress indicator when the first question opens up:

Time to add the font request.

Creating a font request

Your next task is to add requesting downloadable fonts to QuestionActivity.

Create a query string and a request for the downloadable font:

val query = "name=$familyName"
val request = FontRequest(
  "com.google.android.gms.fonts",
  "com.google.android.gms",
  query,
  R.array.com_google_android_gms_fonts_certs
)
Note: make sure you’re using the FontRequest class from android.support.v4.provider package. The one from android.provider is not compatible with support library.

When creating a FontRequest you have to pass:


  • provider authority – only Google provider com.google.android.gms.fonts is available so far
  • provider package – for Google font provider it’s com.google.android.gms
  • query – query string that describes the font you are requesting
  • array of certificates – to verify the provider

To request a new font use requestFont() method from FontsContractCompat. Add following to the end of showFont():

FontsContractCompat.requestFont(
    this,
    request,
    object : FontsContractCompat.FontRequestCallback() {
      override fun onTypefaceRetrieved(typeface: Typeface?) {
        
      }

      override fun onTypefaceRequestFailed(reason: Int) {

      }
    },
    handler
)

Requesting a downloadable font is an asynchronous operation. Method requestFont() passes the result through a FontsContractCompat.FontRequestCallback interface. If the request is successful, FontContractorCompat calls onTypefaceRetreived(). Use the Typeface instance passed to set the font on a View. Enable all the buttons and hide progress indicator:

override fun onTypefaceRetrieved(typeface: Typeface?) {
  buttons.forEach { button -> button.isEnabled = true }

  progressView.visibility = View.INVISIBLE
  fontTextView.typeface = typeface
}
    

In case of an error, FontContractorCompat will call onTypefaceRequestFailed(). Use it to display an error message by calling showError() and passing it error code:

override fun onTypefaceRequestFailed(reason: Int) {
  showError(reason)
}

The last thing you need when requesting fonts is a Handler instance.

Note: In short, a Handler enables you to send code to a different thread which it will then execute.

FontContractorCompat uses it to execute retrieving a font on a Thread associated with that Handler. Make sure you provide a Handler that is not associated with a UI thread.

val handlerThread = HandlerThread("fonts")
handlerThread.start()

handler = Handler(handlerThread.looper)

For convenience, create a private field that will hold the handler and a property that will initialize and retrieve it:

private var handler: Handler? = null

private val handlerThreadHandler: Handler
  get() {
    if (handler == null) {
      val handlerThread = HandlerThread("fonts")
      handlerThread.start()
      handler = Handler(handlerThread.looper)
    }

    return handler ?: throw AssertionError("Set to null by another thread")
  }

Using the handlerThreadHandler property will initialize the handler on the first use and return it.

The call at the end of showFont() should now look like:

FontsContractCompat.requestFont(
    this,
    request,
    object : FontsContractCompat.FontRequestCallback() {
      override fun onTypefaceRetrieved(typeface: Typeface?) {
        buttons.forEach { button -> button.isEnabled = true }

        progressView.visibility = View.INVISIBLE
        fontTextView.typeface = typeface
      }

      override fun onTypefaceRequestFailed(reason: Int) {
        showError(reason)
      }
    },
    handlerThreadHandler
)

Build and run your project. Start the quiz:

Now you can see the text on each question in the appropriate font! :]

Retrieving font information

After you answer a question on the quiz, it would be cool to display a simple fact about the font in question. So your next task will be to retrieve information about a font family.

Go to loadFontFact() in QuestionActivity.

To get information about available fonts use fetchFonts() from FontsContractCompat. Like in the previous task, create a FontRequest first:

val query = "name=$familyName"
val request = FontRequest(
  "com.google.android.gms.fonts",
  "com.google.android.gms",
  query,
  R.array.com_google_android_gms_fonts_certs
)

Then pass it to fetchFonts():

val result = FontsContractCompat.fetchFonts(this@QuestionActivity, null, request)

This will return the information about the requested font family if there is one available with the given name. You’ll look it up in the fonts array of the object returned.

Note: unlike requestFont(), fetchFonts() is synchronous. It will execute on the same thread that it’s called and return information about available fonts.

There are several properties for each font:

  • uri – a URI associated to the font file by the font provider
  • ttcIndex – If providing a TTC_INDEX file, the index to point to. Otherwise, 0.
  • weight – font weight as an integer
  • italic – boolean with value true if the font is italic style

Check that the status code of the result is ok and show the weight of the font to the user:

if (result.statusCode == FontsContractCompat.FontFamilyResult.STATUS_OK) {
  with(textView) {
    text = getString(R.string.correct_answer_message, familyName, result.fonts[0].weight)
    visibility = View.VISIBLE
  }
}

The string R.string.correct_answer_message is already prepared and takes one integer format param that represents the font weight.

Fetching font data is a blocking operation that should execute in the background. Use doAsync and uiThread blocks from Kotlin to execute it on a background thread:

doAsync {
  val query = "name=$familyName"
  val request = FontRequest(
    "com.google.android.gms.fonts",
    "com.google.android.gms",
    query,
    R.array.com_google_android_gms_fonts_certs
  )

  val result = FontsContractCompat.fetchFonts(this@QuestionActivity, null, request)

  if (result.statusCode == FontsContractCompat.FontFamilyResult.STATUS_OK) {
    uiThread {

      with(textView) {
        text = getString(R.string.correct_answer_message, familyName, result.fonts[0].weight)
        visibility = View.VISIBLE
      }
    }
  } 
}

Finally, add error handling and hide the progress indicator. The final code should in loadFontFact()look like:

progressView.visibility = View.INVISIBLE

doAsync {
  val query = "name=$familyName"
  val request = FontRequest(
      "com.google.android.gms.fonts",
      "com.google.android.gms",
      query,
      R.array.com_google_android_gms_fonts_certs
  )

  val result = FontsContractCompat.fetchFonts(this@QuestionActivity, null, request)

  if (result.statusCode == FontsContractCompat.FontFamilyResult.STATUS_OK) {
    uiThread {
      progressView.visibility = View.GONE

      with(textView) {
        text = getString(R.string.correct_answer_message, familyName, result.fonts[0].weight)
        visibility = View.VISIBLE
      }
    }
  } else {
    uiThread {
      showError(result.statusCode)
    }
  }
}

Build and run your project. After answering a question you’ll see a fun fact about the font.

Downloadable fonts as XML resources

You can also define downloadable fonts as XML resources.

Right click on the res\font folder. Choose New\Font resource file. For the name type acme in the dialog.

Add font related attributes to the <font-family> element:

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
  app:fontProviderAuthority="com.google.android.gms.fonts"
  app:fontProviderPackage="com.google.android.gms"
  app:fontProviderQuery="Acme"
  app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
</font-family>

All this looks familiar. Yes, that’s right – you are setting the attributes that you earlier passed to requestFont(). Only this time using XML.

Refer to the created font resource like you did with font family and .ttf files. Open res/activity_main.xml layout and set the acme font to tvFontQuiz textView:

<android.support.v7.widget.AppCompatTextView
  android:id="@+id/tvFontQuiz"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@string/app_name"
  android:textColor="@android:color/black"
  android:textSize="@dimen/logo_text_size"
  android:textStyle="bold"
  app:fontFamily="@font/acme"
  app:layout_constraintRight_toRightOf="parent"
  app:layout_constraintLeft_toLeftOf="parent"               
  app:layout_constraintTop_toBottomOf="@+id/horizontalGuideline" />

Now repeat the process and add the font named Bilbo Swash Caps.

Open res/activity_main.xml and set the bilbo_swash_caps font on tvTheGreat textView:

<android.support.v7.widget.AppCompatTextView
  android:id="@+id/tvTheGreat"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@string/the_great"
  android:textColor="@color/colorAccent"
  android:textSize="@dimen/logo_text_size_small"
  app:fontFamily="@font/bilbo_swash_caps"
  app:layout_constraintBottom_toTopOf="@+id/horizontalGuideline"
  app:layout_constraintLeft_toLeftOf="parent"
  app:layout_constraintRight_toRightOf="parent" />

Build and run your project:

You should see the FontQuiz labels in fonts now. When you first run the app you’ll notice that the font takes a little bit to load before showing because it’s not downloaded and cached yet.

Pre-declaring fonts in manifest

As a bonus – you can specify fonts that Android should preload before your app starts! To do this, you must specify them in the manifest.

Click on the res\values folder, press ⌘N (or File\New) and select Values resource file.

Name the file preloaded_fonts in the dialog.

Add an array of fonts with the resources tag and name it preloaded_fonts:

<array name="preloaded_fonts" translatable="false">
  <item>@font/acme</item>
  <item>@font/bilbo_swash_caps</item>
</array>

Open manifests\AndroidManifest.xml and add the following <meta-data> element inside <application> tag:

<meta-data android:name="preloaded_fonts" android:resource="@array/preloaded_fonts" />

Build and run your project:

Voila! Your fonts are now preloaded and ready to use once the app starts.

And, you have a nice Font Quiz app – it’s time to have fun! Can you score 5 / 5? :]

Where To Go From Here?

Here is the final project with all the code you’ve developed in this tutorial.

Now you know how to add custom and downloadable fonts in your application.

A great place to find more information is the official documentation from Google on
font resources, Fonts in XML and Downloadable fonts.

If you want to browse fonts that are available from the Google font provider check here.

If you have any questions or tips for other custom and downloadable font users, please join in the forum discussion below!

Team

Each tutorial at www.raywenderlich.com is created by a team of dedicated developers so that it meets our high quality standards. The team members who worked on this tutorial are:

Ivan Kušt

Ivan is a Software Engineer from Zagreb, Croatia with more than 8 years of experience in Android development.

The projects he worked on include larger security sensitive mobile banking applications, various smaller applications and even a few simple 2D games

Other Items of Interest

Save time.
Learn more with our video courses.

raywenderlich.com Weekly

Sign up to receive the latest tutorials from raywenderlich.com each week, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

PragmaConf 2016 Come check out Alt U

Our Books

Our Team

Video Team

... 27 total!

iOS Team

... 74 total!

Android Team

... 33 total!

Unity Team

... 15 total!

Articles Team

... 12 total!

Resident Authors Team

... 29 total!

Podcast Team

... 7 total!

Recruitment Team

... 9 total!