Fonts are one of the fastest ways to make an app feel like it has a real identity. That distinctive typeface in your favourite app? It took the developer about 10 minutes to set up — and it's even faster now than it used to be.
In 2014 the only way to use a custom font in Android was to copy a .ttf file into assets/fonts/ and load it in Java with Typeface.createFromAsset(). In 2026 you have three much better options — XML Font Resources, Downloadable Google Fonts with zero asset files, and app-wide font theming that applies your font everywhere in one line. This guide covers all three, plus the legacy approach for when you need to support older APIs.
Three Approaches — Which One Should You Use?
| Approach | Setup | Best For |
|---|---|---|
| Google Fonts (Downloadable) | Zero asset files — font downloads at runtime | Google Fonts library — most popular choice |
| Font Resource (XML) | Font file bundled in res/font/ |
Custom/branded fonts not on Google Fonts |
| Typeface (Legacy) | Font file in assets/fonts/, loaded in code |
API below 26, or legacy codebases |
Method 1 — Google Fonts (Recommended, Zero Asset Files)
This is the cleanest approach in 2026. Android Studio has Google Fonts built in — you pick the font, Android handles the download. No .ttf files in your project, no assets directory.
Using Android Studio's built-in font picker
- Open any layout XML file
- Click on a
TextView - In the Attributes panel find
fontFamily - Click the dropdown → More Fonts
- Search for your font (e.g. "Roboto", "Poppins", "Inter")
- Select Add font to project → choose Downloadable
- Click OK — Android Studio generates all the required XML automatically
Android Studio generates three things automatically:
// 1. res/font/poppins.xml — font family definition
<?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="Poppins"
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
</font-family>
// 2. res/values/font_certs.xml — security certificates (auto-generated) // 3. AndroidManifest.xml — preloaded fonts declaration (auto-generated)
Apply the font in XML
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello with Poppins"
android:fontFamily="@font/poppins"
android:textSize="18sp" />
Method 2 — Font Resource in res/font/ (For Custom/Branded Fonts)
When your brand uses a custom typeface that isn't on Google Fonts — a purchased font, a company-specific typeface — bundle it directly in your app using the Font Resource system introduced in API 26.
Step 1: Add font files to res/font/
// Create the directory: res/font/ // Add your font files with lowercase names — no spaces, no hyphens // res/font/montserrat_regular.ttf // res/font/montserrat_bold.ttf // res/font/montserrat_italic.ttf
Step 2: Create a font family XML (optional but recommended)
A font family XML lets you define all weights and styles in one place. Android automatically picks the right weight for bold/italic text:
<!-- res/font/montserrat.xml -->
<?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/montserrat_regular" />
<font
android:fontStyle="normal"
android:fontWeight="700"
android:font="@font/montserrat_bold" />
<font
android:fontStyle="italic"
android:fontWeight="400"
android:font="@font/montserrat_italic" />
</font-family>
Step 3: Apply in XML
<!-- Apply the font family -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Branded heading"
android:fontFamily="@font/montserrat"
android:textStyle="bold"
android:textSize="24sp" />
<!-- Apply a specific weight directly -->
<TextView
android:fontFamily="@font/montserrat_regular"
android:text="Regular body text" />
Apply in code with ViewBinding (Kotlin)
import androidx.core.content.res.ResourcesCompat // Load font resource in code val typeface = ResourcesCompat.getFont(context, R.font.montserrat) binding.tvTitle.typeface = typeface // Or with a specific style val boldTypeface = ResourcesCompat.getFont(context, R.font.montserrat_bold) binding.tvHeading.typeface = boldTypeface
Apply Font App-Wide via Theme (Most Efficient)
This is the best thing most tutorials skip entirely. Instead of setting fontFamily on every single TextView, set it once in your app theme and it applies everywhere automatically:
<!-- res/values/themes.xml -->
<resources>
<style name="Theme.MyApp" parent="Theme.Material3.DayNight">
<!-- Apply custom font to ALL text in the app -->
<item name="fontFamily">@font/poppins</item>
<!-- Or use Material3 type attributes for finer control -->
<item name="textAppearanceHeadlineLarge">@style/TextAppearance.MyApp.HeadlineLarge</item>
<item name="textAppearanceBodyMedium">@style/TextAppearance.MyApp.BodyMedium</item>
</style>
<!-- Custom text appearances with your font -->
<style name="TextAppearance.MyApp.HeadlineLarge"
parent="TextAppearance.Material3.HeadlineLarge">
<item name="fontFamily">@font/montserrat_bold</item>
</style>
<style name="TextAppearance.MyApp.BodyMedium"
parent="TextAppearance.Material3.BodyMedium">
<item name="fontFamily">@font/montserrat_regular</item>
</style>
</resources>
<!-- AndroidManifest.xml — apply theme to whole app -->
<application
android:theme="@style/Theme.MyApp"
... />
Legacy Method — Typeface from Assets (API below 26)
If you need to support devices below API 26 and can't use the Font Resource system, the original assets/fonts/ approach still works. Use Kotlin and ViewBinding instead of the old Java pattern:
Step 1: Add font to assets
// Create: src/main/assets/fonts/ // Add your font: src/main/assets/fonts/custom_font.ttf
Step 2: Load with Typeface in Kotlin
import android.graphics.Typeface
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// Load font from assets
val typeface = Typeface.createFromAsset(assets, "fonts/custom_font.ttf")
// Apply to views
binding.tvTitle.typeface = typeface
binding.tvSubtitle.typeface = typeface
// Apply bold style programmatically
binding.tvHeading.setTypeface(typeface, Typeface.BOLD)
}
}
Reusable extension function for the assets approach
// ViewExtensions.kt
fun TextView.setCustomFont(context: Context, fontPath: String) {
typeface = Typeface.createFromAsset(context.assets, fontPath)
}
// Usage
binding.tvTitle.setCustomFont(this, "fonts/custom_font.ttf")
binding.tvBody.setCustomFont(this, "fonts/custom_font.ttf")
Typeface.createFromAsset() reads from disk every time it's called. For lists or repeated use, cache the Typeface in a companion object or ViewModel to avoid repeated I/O:
companion object {
private var cachedTypeface: Typeface? = null
fun getTypeface(context: Context): Typeface {
if (cachedTypeface == null) {
cachedTypeface = Typeface.createFromAsset(
context.assets, "fonts/custom_font.ttf"
)
}
return cachedTypeface!!
}
}
Best Practices
- Use Google Fonts for standard typefaces — if your font is on Google Fonts, always use the downloadable approach. No APK size increase, OS-level caching, zero maintenance.
- Set fonts in the theme, not per-view — for branded apps, define your typography in
themes.xmlusing Material3 text appearance attributes. One change updates every text element in the app simultaneously. - Use lowercase filenames with underscores for font files —
res/font/files follow the same naming rules as drawables. No uppercase, no hyphens.poppins_bold.ttf✅,Poppins-Bold.ttf❌ - Define font families for multiple weights — create a font family XML in
res/font/that includes all weights. Android automatically selects the right weight when you usetextStyle="bold". - Cache Typeface when using the legacy approach —
createFromAsset()reads from disk. In RecyclerView or any repeated context, cache the Typeface instance and reuse it.
Frequently Asked Questions
How do I add a custom font in Android with Kotlin?
Place your .ttf or .otf file in res/font/ and reference it with android:fontFamily="@font/your_font" in XML. For Google Fonts, use Android Studio's font picker which generates all required files automatically. For app-wide fonts, add fontFamily to your theme in themes.xml.
What is the difference between Google Fonts and Font Resources?
Google Fonts (downloadable) fetch at runtime from Google's servers with OS-level caching — no font files in your APK. Font Resources bundle the font inside res/font/ in your APK — works offline but increases APK size. Use Google Fonts for standard typefaces, Font Resources for custom branded fonts.
How do I apply a custom font to all text in the app?
Add <item name="fontFamily">@font/your_font</item> to your app theme in themes.xml and apply the theme in AndroidManifest.xml. This applies your font to every text-based component in the entire app automatically.
Can I still use Typeface.createFromAsset()?
Yes it still works — but it's the legacy approach. Use Font Resources or Google Fonts for new projects. If you do use createFromAsset(), cache the Typeface instance to avoid repeated disk reads, especially inside RecyclerView adapters.
- Google Fonts — zero asset files, OS-cached, use for any font on Google Fonts
- Font Resource (
res/font/) — bundle custom/branded fonts, set in XML with@font/name - App-wide font via theme — add
fontFamilytothemes.xml, applies everywhere automatically - Font family XML — define all weights together, Android picks the right one automatically
- Legacy Typeface — still works, cache the instance, avoid for new projects
- Font filenames must be lowercase with underscores — no uppercase, no hyphens
- Use
ResourcesCompat.getFont()to load font resources in Kotlin code