Typeface — это класс Android SDK из пакета android.graphics, который представляет начертание шрифта и используется для кастомизации текста в TextView и других UI-компонентах. Typeface определяет семейство шрифта, его вес (normal, bold) и стиль (normal, italic). По данным Google Developers, Typeface поддерживает загрузку из файлов TTF, OTF, XML-шрифтов и системных ресурсов. Это центральный класс для управления типографикой в Android-приложениях.
Главное
Typeface — это класс Android, инкапсулирующий информацию о шрифте: его семейство (Roboto, Arial, Serif) и стилевые модификаторы (жирность, курсив). В отличие от UIFont в iOS, Typeface не содержит информацию о размере — размер текста задаётся отдельно через свойство textSize в TextView или TextStyle в Spannable. Typeface отвечает только за начертание и гарнитуру шрифта.
Класс доступен на всех уровнях API. До Android 4.4 Typeface поддерживал только ограниченный набор системных шрифтов: DEFAULT, DEFAULT_BOLD, MONOSPACE, SERIF, SANS_SERIF. Начиная с Android 8.0 (API 26) появилась поддержка загрузки кастомных шрифтов через XML-ресурсы, а Android 10 добавил поддержку вариативных шрифтов.
Android предоставляет несколько встроенных экземпляров Typeface: Typeface.DEFAULT — системный шрифт Roboto (Material) или Noto (AOSP), DEFAULT_BOLD — жирная версия, MONOSPACE — моноширинный шрифт для кода, SERIF — шрифт с засечками (Noto Serif), SANS_SERIF — гротеск (Noto Sans). Эти константы доступны без контекста и не требуют разрешений на чтение файлов.
Система Android использует Typeface для отрисовки всего текста, включая системные UI, заголовки, подписи и уведомления. Каждое приложение может переопределить шрифт по умолчанию через тему (android:fontFamily) или программно через setTypeface(). Typeface применяется ко всем компонентам, унаследованным от TextView: кнопкам, EditText и кастомным вьюхам.
Android 8.0+ позволяет добавлять шрифты в res/font и использовать их через XML-ресурсы. Файл шрифта (TTF или OTF) помещается в res/font, после чего создаётся ссылка R.font.font_name. Typeface загружается через ResourcesCompat.getFont(context, R.font.font_name). Этот способ предпочтительнее, так как шрифт компилируется в APK и поддерживает системы вёрстки ProGuard.
Ресурсный способ также поддерживает семейства шрифтов (font family) через XML-файл в res/font: можно указать несколько файлов для разных начертаний (regular, bold, italic) и система автоматически выберет нужный файл при вызове setTypeface. Это упрощает типографику — достаточно задать fontFamily в теме, а Android сам подберёт подходящий файл.
Метод Typeface.create(Typeface family, int style) создаёт экземпляр шрифта с указанным семейством и стилем. Если семейство уже имеет запрошенный стиль, возвращается существующий экземпляр. Если стиль отсутствует, Android синтезирует его — применяет фальсификацию псевдожирности или искусственного курсива к базовому шрифту.
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
Синтезированный псевдоболд может выглядеть некачественно на тонких шрифтах. Для лучшего результата используйте файл шрифта с настоящим bold-начертанием. Typeface.create() с несуществующим стилем не выбрасывает исключение, а возвращает ближайший доступный вариант.
Для загрузки Typeface из assets используется Typeface.createFromAsset(assetManager, path). Шрифт помещается в директорию src/main/assets/fonts/, а путь указывается относительно assets. Этот способ работает на всех версиях Android, но не поддерживает семейства шрифтов и требует указания конкретного файла для каждого начертания.
Метод Typeface.createFromFile(File) загружает шрифт из произвольного файла на файловой системе. Это полезно для шрифтов, скачанных из сети или скопированных во внутреннее хранилище приложения. createFromFile также не требует контекста, что удобно для фоновых задач, но файл должен быть доступен для чтения.
Многократная загрузка Typeface из assets через createFromAsset может приводить к созданию дублирующихся объектов. Каждый вызов createFromAsset загружает файл заново. Рекомендуется реализовать кэш Typeface через HashMap, где ключом выступает путь к файлу, а значением — загруженный экземпляр. Это особенно актуально для списков с разными типами шрифта.
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")
Кэш в памяти гарантирует, что один шрифт загружается только один раз за сессию приложения. При смене конфигурации (поворот экрана) кэш сохраняется, так как находится в объекте companion. Для очистки кэша при нехватке памяти используйте WeakHashMap или прослушивайте onTrimMemory.
Typeface применяется к TextView через метод setTypeface(Typeface tf) или setTypeface(Typeface tf, int style). Второй вариант позволяет изменить стиль (bold/italic) относительно текущего шрифта. В XML используется атрибут android:fontFamily с ссылкой на шрифт или системное семейство. Для программной установки вызов setTypeface(monospaceTypeface) заменит шрифт на указанный.
Typeface влияет на весь текст TextView. Если требуется разный шрифт в одной строке, используется SpannableString с TypefaceSpan. TypefaceSpan принимает Typeface или family и применяется к диапазону символов. Это единственный способ смешивать шрифты внутри одного TextView без вложенных компонентов.
Применим TypefaceSpan только к части строки. Например, значение переменной в тексте должно быть моноширинным, а остальной текст — системным. Создаётся SpannableString, и на нужный диапазон устанавливается TypefaceSpan с MONOSPACE Typeface. Остальная часть текста остаётся с исходным шрифтом TextView.
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
Текст "variableName" отобразится моноширинным шрифтом синего цвета, а слово "Код:" останется системным шрифтом. TypefaceSpan можно комбинировать с любыми другими спанами для точного контроля над каждым участком текста.
Android поддерживает несколько форматов шрифтов: TrueType (TTF), OpenType (OTF) и Web Open Font Format (WOFF2) начиная с Android 10. TTF и OTF — основные форматы для кастомных шрифтов. XML-шрифты (Font Family) не являются отдельным форматом, а служат описанием, какой файл использовать для каждого начертания.
Для использования кастомного шрифта через res/font создайте XML-файл семейства, где указываются пути к файлам шрифтов для regular, bold и italic. Затем в теме приложения укажите android:fontFamily="@font/custom_family". Все TextView, использующие эту тему, автоматически получат корректное начертание для каждого стиля.
Если шрифт скачивается из сети, сохраните его в filesDir или cacheDir и загрузите через Typeface.createFromFile. После загрузки обновите Typeface в TextView. Для асинхронной загрузки используйте coroutine или DownloadManager, а после завершения — пост в UI поток через Handler. Это типичный сценарий для приложений с кастомной типографикой, загружаемой по требованию.
// 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
Перед загрузкой проверьте доступность файла: если файл повреждён или невалидный, Typeface.createFromFile бросит RuntimeException. Рекомендуется оборачивать вызов в try-catch и в случае ошибки оставлять системный шрифт по умолчанию.
В Jetpack Compose Typeface Android SDK не используется напрямую. Вместо этого Compose предоставляет FontFamily и FontWeight для типографики. FontFamily загружается через Font.Ressource и Font.File. Система типографики Compose задаётся через MaterialTheme.typography, где каждому стилю (h1, body1, button) можно назначить кастомный FontFamily.
Для загрузки шрифта из resources Compose использует Font(R.font.font_name, weight, style). Шрифт из assets загружается через Font(assetPath = "fonts/custom.otf", weight, style). После определения шрифта он передаётся в Typography, а затем применяется через MaterialTheme.typography.bodyLarge и аналогичные стили.
Если есть готовый Typeface, созданный через Android SDK, его можно использовать в Compose через TypefaceAdapter или создав FontFamily на основе Typeface. Для этого получите Typeface из Typeface.create и передайте его в FontFamily.Custom(listOf(Font(typeface))). Однако рекомендуется использовать нативный подход с Font.Ressource, так как он лучше оптимизирован для Compose.
Загрузка шрифтов из файлов — потенциально дорогая операция. Каждый вызов Typeface.createFromAsset или Typeface.createFromFile читает файл с диска, парсит его и создаёт объект Typeface. Для шрифтов размером 1-2 МБ это занимает до 10-50 мс на холодном запуске. Кэширование Typeface — обязательная практика для приложений с кастомными шрифтами.
Android SDK не кэширует шрифты, созданные через createFromAsset или createFromFile. В отличие от системных шрифтов, которые предзагружены в процессе Zygote, кастомные шрифты загружаются при каждом обращении. Рекомендуется использовать LruCache или ConcurrentHashMap с ключом из идентификатора шрифта. Размер кэша — 10-20 экземпляров, что покрывает типичный набор шрифтов приложения.
Android 8.0+ оптимизирует загрузку шрифтов через XML Font Family. При указании android:fontFamily="@font/my_family" в XML-разметке, Android загружает шрифт лениво — только когда компонент становится видимым. Система также кэширует шрифты, загруженные через ResourcesCompat.getFont(), в глобальном кэше процессов. Это делает ресурсный способ наиболее производительным.
При использовании Typeface в адаптерах RecyclerView важно не загружать шрифт в методе onBindViewHolder. Вызовите загрузку один раз при создании адаптера или используйте ViewHolder с предварительно загруженным Typeface. Если каждый элемент списка требует уникального шрифта, реализуйте кэш через WeakHashMap и очищайте его при проскролле мимо видимых позиций для экономии памяти.
Часто задаваемые вопросы
Typeface — это конкретный экземпляр шрифта для программного использования. FontFamily — XML-ресурс, описывающий группу файлов шрифта для разных начертаний (regular, bold, italic). В runtime FontFamily преобразуется в Typeface через ResourcesCompat.getFont. Typeface можно создать напрямую из файла, минуя FontFamily.
Используйте Typeface.createFromFile(File) или Typeface.DEFAULT. Эти методы не требуют контекста, так как работают с файловой системой или встроенными константами. Для загрузки из assets или ресурсов контекст обязателен, так как нужен доступ к AssetManager и ресурсам приложения.
Нет, WebView использует CSS-свойство font-family для указания шрифтов. Чтобы использовать кастомный шрифт в WebView, поместите файл шрифта в assets и укажите его через @font-face в CSS. Typeface Android SDK работает только с нативными UI-компонентами (TextView и наследниками).
Да, начиная с Android 10 (API 29). Вариативные шрифты загружаются через ResourcesCompat.getFont или Typeface.createFromFile. Для настройки осей вариативности (weight, width) используется FontStyle в Compose или XML-атрибуты. Программно изменить ось можно только через низкоуровневые API Skia.
Наиболее частые причины: файл шрифта отсутствует в проекте, указано неверное имя файла, шрифт повреждён, или используется синтезированный стиль, которого нет в файле. Проверьте, что файл добавлен в res/font или assets, и что его имя указано без расширения в случае ресурсного способа.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также