Typeface — is an Android SDK class from the android.graphics package that represents a font typeface and is used for text customization in TextView and other UI components. Typeface defines the font family, its weight (normal, bold) and style (normal, italic). According to Google Developers, Typeface supports loading from TTF, OTF files, XML fonts and system resources. It is the central class for typography management in Android applications.
Key Takeaways
Typeface — is an Android class that encapsulates font information: its family (Roboto, Arial, Serif) and style modifiers (boldness, italic). Unlike UIFont in iOS, Typeface does not contain size information — text size is set separately via the textSize property in TextView or TextStyle in Spannable. Typeface is only responsible for the typeface and font design.
The class is available at all API levels. Before Android 4.4, Typeface only supported a limited set of system fonts: DEFAULT, DEFAULT_BOLD, MONOSPACE, SERIF, SANS_SERIF. Starting with Android 8.0 (API 26), support for loading custom fonts via XML resources was added, and Android 10 added support for variable fonts.
Android provides several built-in Typeface instances: Typeface.DEFAULT — system font Roboto (Material) or Noto (AOSP), DEFAULT_BOLD — bold version, MONOSPACE — monospace font for code, SERIF — serif font (Noto Serif), SANS_SERIF — sans-serif (Noto Sans). These constants are available without context and do not require file read permissions.
The Android system uses Typeface to render all text, including system UI, titles, captions and notifications. Each application can override the default font via theme (android:fontFamily) or programmatically via setTypeface(). Typeface applies to all components inherited from TextView: buttons, EditText and custom views.
Android 8.0+ allows adding fonts to res/font and using them via XML resources. The font file (TTF or OTF) is placed in res/font, after which a reference R.font.font_name is created. Typeface is loaded via ResourcesCompat.getFont(context, R.font.font_name). This method is preferable because the font is compiled into the APK and supports ProGuard build systems.
The resource approach also supports font families via an XML file in res/font: you can specify multiple files for different typefaces (regular, bold, italic) and the system will automatically select the appropriate file when setTypeface is called. This simplifies typography — just set fontFamily in the theme, and Android will pick the right file automatically.
The Typeface.create(Typeface family, int style) method creates a font instance with the specified family and style. If the family already has the requested style, the existing instance is returned. If the style is missing, Android synthesizes it — applying faux bold or artificial italic to the base font.
val boldTypeface = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD)
val italicTypeface = Typeface.create(Typeface.MONOSPACE, Typeface.ITALIC)
val customTypeface = ResourcesCompat.getFont(context, R.font.montserrat_regular)
textView.typeface = boldTypeface
Synthesized faux bold may look low quality on thin fonts. For best results, use a font file with an actual bold typeface. Typeface.create() with a non-existent style does not throw an exception but returns the nearest available variant.
To load Typeface from assets, use Typeface.createFromAsset(assetManager, path). The font is placed in the src/main/assets/fonts/ directory, and the path is specified relative to assets. This method works on all Android versions but does not support font families and requires specifying a specific file for each typeface.
The Typeface.createFromFile(File) method loads a font from an arbitrary file on the file system. This is useful for fonts downloaded from the network or copied to the app’s internal storage. createFromFile also does not require context, which is convenient for background tasks, but the file must be readable.
Loading Typeface from assets repeatedly via createFromAsset can lead to duplicate object creation. Each createFromAsset call reloads the file. It is recommended to implement a Typeface cache using a HashMap, where the key is the file path and the value is the loaded instance. This is especially relevant for lists with different font types.
object TypefaceCache {
private val cache = mutableMapOf<String, Typeface>()
fun getTypeface(context: Context, filename: String): Typeface {
return cache.getOrPut(filename) {
Typeface.createFromAsset(context.assets, "fonts/$filename")
}
}
}
// Usage
val typeface = TypefaceCache.getTypeface(context, "Roboto-Bold.ttf")
An in-memory cache ensures that a font is loaded only once per app session. On configuration changes (screen rotation), the cache persists because it resides in a companion object. To clear the cache on low memory, use WeakHashMap or listen for onTrimMemory.
Typeface is applied to TextView via the setTypeface(Typeface tf) method or setTypeface(Typeface tf, int style). The second variant allows changing the style (bold/italic) relative to the current font. In XML, the android:fontFamily attribute is used with a reference to the font or system family. For programmatic setup, calling setTypeface(monospaceTypeface) replaces the font with the specified one.
Typeface affects the entire TextView text. If different fonts are needed in a single line, use SpannableString with TypefaceSpan. TypefaceSpan accepts Typeface or family and is applied to a character range. This is the only way to mix fonts within a single TextView without nested components.
Apply TypefaceSpan to only part of the string. For example, a variable value in text should be monospace while the rest of the text remains system. Create a SpannableString and set a TypefaceSpan with MONOSPACE Typeface on the desired range. The rest of the text retains the original TextView font.
val text = "Code: variableName"
val spannable = SpannableString(text)
spannable.setSpan(
TypefaceSpan(Typeface.MONOSPACE),
5, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
spannable.setSpan(
ForegroundColorSpan(Color.BLUE),
5, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
textView.text = spannable
The text “variableName” will appear in a monospace blue font, while the word “Code:” remains in the system font. TypefaceSpan can be combined with any other spans for precise control over each text segment.
Android supports several font formats: TrueType (TTF), OpenType (OTF) and Web Open Font Format (WOFF2) starting with Android 10. TTF and OTF are the main formats for custom fonts. XML fonts (Font Family) are not a separate format but serve as a description of which file to use for each typeface.
To use a custom font via res/font, create a family XML file specifying the paths to font files for regular, bold and italic. Then in the app theme, specify android:fontFamily="@font/custom_family". All TextView instances using this theme will automatically get the correct typeface for each style.
If a font is downloaded from the network, save it to filesDir or cacheDir and load it via Typeface.createFromFile. After loading, update the Typeface in TextView. For asynchronous loading, use coroutine or DownloadManager, and after completion, post to the UI thread via Handler. This is a typical scenario for apps with custom typography loaded on demand.
// Save font file to internal storage
val fontFile = File(context.cacheDir, "downloaded-font.otf")
fontFile.outputStream().use { output ->
// inputStream from network
inputStream.copyTo(output)
}
// Create Typeface from file
val downloadedTypeface = Typeface.createFromFile(fontFile)
textView.typeface = downloadedTypeface
Before loading, check file availability: if the file is corrupted or invalid, Typeface.createFromFile throws a RuntimeException. It is recommended to wrap the call in a try-catch and fall back to the default system font on error.
In Jetpack Compose, the Android SDK Typeface is not used directly. Instead, Compose provides FontFamily and FontWeight for typography. FontFamily is loaded via Font.Resource and Font.File. The Compose typography system is defined via MaterialTheme.typography, where each style (h1, body1, button) can be assigned a custom FontFamily.
To load a font from resources, Compose uses Font(R.font.font_name, weight, style). A font from assets is loaded via Font(assetPath = "fonts/custom.otf", weight, style). After defining the font, it is passed to Typography, and then applied via MaterialTheme.typography.bodyLarge and similar styles.
If you have an existing Typeface created via the Android SDK, it can be used in Compose via TypefaceAdapter or by creating a FontFamily based on the Typeface. Obtain the Typeface from Typeface.create and pass it to FontFamily.Custom(listOf(Font(typeface))). However, the native approach with Font.Resource is recommended as it is better optimized for Compose.
Loading fonts from files is a potentially expensive operation. Each call to Typeface.createFromAsset or Typeface.createFromFile reads the file from disk, parses it and creates a Typeface object. For fonts sized 1-2 MB, this takes 10-50 ms on cold start. Caching Typeface is mandatory practice for apps with custom fonts.
The Android SDK does not cache fonts created via createFromAsset or createFromFile. Unlike system fonts, which are preloaded in the Zygote process, custom fonts are loaded on each access. It is recommended to use LruCache or ConcurrentHashMap with a font identifier as key. A cache size of 10-20 instances covers a typical app font set.
Android 8.0+ optimizes font loading through XML Font Family. When specifying android:fontFamily="@font/my_family" in XML layout, Android loads the font lazily — only when the component becomes visible. The system also caches fonts loaded via ResourcesCompat.getFont() in a global process cache. This makes the resource approach the most performant.
When using Typeface in RecyclerView adapters, it is important not to load fonts in the onBindViewHolder method. Perform loading once when creating the adapter or use a ViewHolder with a preloaded Typeface. If each list item requires a unique font, implement a cache using WeakHashMap and clear it when scrolling past visible positions to save memory.
Frequently Asked Questions
Typeface — is a concrete font instance for programmatic use. FontFamily — is an XML resource describing a group of font files for different typefaces (regular, bold, italic). At runtime, FontFamily is converted to Typeface via ResourcesCompat.getFont. Typeface can be created directly from a file, bypassing FontFamily.
Use Typeface.createFromFile(File) or Typeface.DEFAULT. These methods do not require context as they work with the file system or built-in constants. For loading from assets or resources, context is required because access to AssetManager and app resources is needed.
No, WebView uses the CSS font-family property to specify fonts. To use a custom font in WebView, place the font file in assets and specify it via @font-face in CSS. The Typeface Android SDK only works with native UI components (TextView and its descendants).
Yes, starting with Android 10 (API 29). Variable fonts are loaded via ResourcesCompat.getFont or Typeface.createFromFile. To configure variation axes (weight, width), use FontStyle in Compose or XML attributes. Programmatic axis changes can only be done through low-level Skia APIs.
The most common reasons: the font file is missing from the project, the file name is incorrect, the font is corrupted, or a synthesized style is used that does not exist in the file. Verify that the file is added to res/font or assets, and that its name is specified without the extension for the resource approach.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also