Custom Fonts in Android: Kotlin XML Guide

Custom fonts can significantly enhance the visual appeal and branding of your Android application. Using custom fonts in your app can make it stand out and provide a unique user experience. In this guide, we’ll explore how to add custom fonts to your Android project (under res/font/) and apply them programmatically in Kotlin XML development.

Why Use Custom Fonts?

  • Branding: Use fonts that match your brand identity.
  • User Experience: Improve readability and visual appeal.
  • Uniqueness: Differentiate your app from others with distinctive typography.

Step 1: Add Custom Font Files to Your Project

The first step is to add your custom font files to your Android project. These files typically come in .ttf (TrueType Font) or .otf (OpenType Font) formats. Here’s how to add them:

1. Create a font Directory

If it doesn’t already exist, create a font directory under the res directory. This is where you will store all your font files.

app/
  └── src/
      └── main/
          └── res/
              └── font/
                  └── # Font files (.ttf or .otf) will go here

2. Copy Font Files

Copy your .ttf or .otf font files into the res/font/ directory. For example:

app/
  └── src/
      └── main/
          └── res/
              └── font/
                  ├── my_custom_font_regular.ttf
                  └── my_custom_font_bold.ttf

3. Create Font Resource XML (Optional)

To take advantage of Android’s font family feature (especially for handling different font weights like regular and bold), create a font resource XML file. In the font directory, create a new XML file (e.g., my_custom_font.xml):

<?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:fontStyle="normal"
        android:fontWeight="400"
        android:font="@font/my_custom_font_regular"
        app:fontStyle="normal"
        app:fontWeight="400"
        app:font="@font/my_custom_font_regular" />

    <font
        android:fontStyle="normal"
        android:fontWeight="700"
        android:font="@font/my_custom_font_bold"
        app:fontStyle="normal"
        app:fontWeight="700"
        app:font="@font/my_custom_font_bold" />

</font-family>

In this XML:

  • android:fontStyle: Specifies whether the font is italic or normal.
  • android:fontWeight: Specifies the weight of the font (e.g., 400 for regular, 700 for bold).
  • android:font: Points to the actual font file.

Note that if you’re supporting older versions of Android (API < 26), you’ll need to include the app: attributes.

Step 2: Apply Custom Fonts in XML

You can directly apply custom fonts in your XML layouts by referencing them. There are two primary ways to do this:

1. Using android:fontFamily

If you’ve created a font resource XML (e.g., my_custom_font.xml), you can use the android:fontFamily attribute in your TextView.

<TextView
    android:id="@+id/myTextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello, Custom Font!"
    android:fontFamily="@font/my_custom_font" />

The android:fontFamily attribute allows you to specify the font family defined in the XML resource.

2. Direct Reference (Without Font Family XML)

Alternatively, you can directly reference a specific font file using the android:typeface attribute (though android:fontFamily is recommended for better flexibility).

<TextView
    android:id="@+id/myTextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello, Custom Font!"
    android:typeface="normal"
    android:fontFamily="@font/my_custom_font_regular" />

Here, android:fontFamily is directly pointing to the font file. Although android:typeface is set to normal (to ensure it doesn’t interfere), the fontFamily is the one effectively setting the font.

Step 3: Apply Custom Fonts Programmatically in Kotlin

You can also apply custom fonts programmatically in your Kotlin code. This is useful when you need to dynamically change the font or apply it to views created programmatically.

1. Get a Typeface Instance

Use the ResourcesCompat.getFont() method to obtain a Typeface instance from your font resource.

import androidx.core.content.res.ResourcesCompat
import android.graphics.Typeface
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val textView: TextView = findViewById(R.id.myTextView)

        val typeface: Typeface? = ResourcesCompat.getFont(this, R.font.my_custom_font)
        textView.typeface = typeface
    }
}

Here, ResourcesCompat.getFont() is used to load the font resource specified by R.font.my_custom_font. Then, textView.typeface is set to this typeface.

2. Handle Font Loading Errors

It’s a good practice to handle potential errors that might occur when loading fonts.

import androidx.core.content.res.ResourcesCompat
import android.graphics.Typeface
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val textView: TextView = findViewById(R.id.myTextView)

        val typeface: Typeface? = try {
            ResourcesCompat.getFont(this, R.font.my_custom_font)
        } catch (e: Exception) {
            Log.e("FontError", "Failed to load font", e)
            null
        }

        textView.typeface = typeface
    }
}

This code includes a try-catch block to log any errors that occur while loading the font, ensuring your app doesn’t crash and provides helpful debugging information.

Complete Example

Here’s a complete example of using custom fonts in an Android project:

1. Create the res/font/my_custom_font.xml 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/my_custom_font_regular" />

</font-family>

2. Layout XML (res/layout/activity_main.xml):

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/myTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello, Custom Font!"
        android:textSize="24sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

3. Kotlin Code (MainActivity.kt):

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import androidx.core.content.res.ResourcesCompat
import android.graphics.Typeface

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val textView: TextView = findViewById(R.id.myTextView)
        val typeface: Typeface? = ResourcesCompat.getFont(this, R.font.my_custom_font)

        textView.typeface = typeface
    }
}

Conclusion

Adding and applying custom fonts in your Android application can significantly improve its visual appeal and user experience. Whether you choose to apply fonts directly in XML layouts or programmatically in Kotlin, the key is to ensure your font files are correctly added to the res/font/ directory and properly referenced. By following the steps outlined in this guide, you can easily integrate custom fonts and elevate your app’s design.