Jetpack Compose Typography: как настроить роли текста

Актуально на 22 июля 2026 года.
Jetpack Compose Typography — это система текстовых ролей, которая задает единую визуальную иерархию Android-приложения через объект Typography и стили TextStyle. Вместо ручной настройки каждого Text разработчик назначает роли заголовка, основного текста, подписи или кнопки, а затем централизованно управляет шрифтом, размером, весом и интервалами.
Зачем приложению нужны текстовые роли
Типографическая роль описывает не конкретную строку, а ее функцию в интерфейсе. Например, название экрана должно отличаться от текста карточки, а подпись к полю — от основного описания. Такой подход помогает сохранить контраст и порядок даже тогда, когда экранов становится много, а контент меняется.
Без ролевой модели команда часто задает размеры и начертания локально: один разработчик использует 20 sp для заголовка, другой — 22 sp, а третий добавляет жирность вручную. В результате интерфейс теряет целостность. Typography превращает набор разрозненных параметров в дизайн-токены, доступные из темы приложения.
Хорошая типографика в Compose начинается не с выбора размера шрифта, а с определения назначения каждого текстового элемента.
Как устроена Typography в Material 3
В Material 3 объект Typography содержит готовые роли для крупных заголовков, заголовков разделов, названий компонентов, основного текста и меток. Основной доступ к ним выполняется через MaterialTheme.typography. Например, MaterialTheme.typography.displayLarge подходит для очень крупного текста, bodyLarge — для обычного содержимого, а labelMedium — для компактной подписи.
Стандартный набор Material 3 включает роли displayLarge, displayMedium и displaySmall; headlineLarge, headlineMedium и headlineSmall; titleLarge, titleMedium и titleSmall; bodyLarge, bodyMedium и bodySmall; labelLarge, labelMedium и labelSmall. Название роли подсказывает ее место в иерархии, но не запрещает адаптировать ее под конкретный продукт.
- Display — крупные промо-заголовки, обложки и ключевые сообщения.
- Headline — заголовки экранов и заметные разделы.
- Title — названия карточек, диалогов и элементов навигации.
- Body — основной текст, описания, подсказки и длинные сообщения.
- Label — короткие подписи, фильтры, кнопки и вспомогательные метки.
Роль не определяет цвет или отступы. Typography отвечает прежде всего за параметры текста: fontFamily, fontSize, fontWeight, fontStyle, letterSpacing, lineHeight и некоторые дополнительные свойства TextStyle. Цвет, выравнивание и поведение при переносе обычно задаются в месте использования либо отдельным компонентом дизайна.
Material 2 и Material 3: какую модель выбрать
В проектах на Material 2 встречаются роли h1, h2, h3, h4, h5, h6, subtitle1, subtitle2, body1, body2, button, caption и overline. В Material 3 используется другая система имен: display, headline, title, body и label. Эти наборы нельзя механически смешивать: сначала определите дизайн-систему проекта, затем используйте соответствующий тип Typography и импорты.
Если приложение постепенно переходит на Material 3, полезно создать слой собственных семантических ролей поверх стандартных стилей. Например, роль AppTextStyle.ScreenTitle может ссылаться на headlineSmall, а AppTextStyle.CardTitle — на titleMedium. Тогда миграция и дальнейшая настройка не потребуют поиска каждого вызова Text по всему проекту.
Настройка базовой типографики темы
Начните с одного объекта Typography в файле темы. В простом проекте достаточно изменить несколько ролей, сохранив остальные значения Material 3. Практический принцип таков: крупные заголовки должны иметь заметную иерархию, основной текст — комфортное чтение, а label-роли — достаточную компактность без чрезмерного уменьшения.
Пример настройки можно описать так: val AppTypography = Typography(headlineSmall = TextStyle(fontSize = 24.sp, lineHeight = 32.sp, fontWeight = FontWeight.SemiBold), bodyLarge = TextStyle(fontSize = 16.sp, lineHeight = 24.sp), labelLarge = TextStyle(fontSize = 14.sp, fontWeight = FontWeight.Medium)). Затем объект передается в MaterialTheme через параметр typography = AppTypography.
Не обязательно переопределять все пятнадцать ролей. Если роль не указана, используйте значения по умолчанию и меняйте только те стили, которые соответствуют визуальной системе продукта. Так тема остается компактной и понятной, а случайные различия между экранами не появляются из-за копирования больших конфигураций.
Подключение собственного шрифта в Compose
Собственный шрифт обычно добавляют в ресурсный каталог шрифтов Android, после чего описывают его через FontFamily. Для семейства с несколькими начертаниями создайте отдельные Font для regular, medium, semibold или bold и укажите соответствующий FontWeight. Compose сможет выбрать нужный файл, когда стиль запрашивает конкретный вес.
Пример логики конфигурации: val AppFontFamily = FontFamily(Font(R.font.app_regular, FontWeight.Normal), Font(R.font.app_medium, FontWeight.Medium), Font(R.font.app_bold, FontWeight.Bold)). После этого передайте fontFamily = AppFontFamily в Typography или в отдельный TextStyle. Названия ресурсов должны соответствовать реальным файлам проекта.
Если у семейства нет отдельного файла для нужного веса, система может имитировать начертание или использовать ближайший доступный вариант. Для интерфейса это не всегда приемлемо: искусственно утолщенный шрифт меняет ширину строк и форму букв. Поэтому заранее проверьте, какие веса действительно поддерживает выбранное семейство.
Размер, вес, интерлиньяж и трекинг
Размер текста в Compose задается в sp, а не в dp. Единица sp учитывает пользовательские настройки масштаба шрифта и поэтому лучше подходит для доступного интерфейса. Фиксировать размер через dp не следует: такой текст может стать слишком мелким или, наоборот, нарушить композицию при изменении системного масштаба.
FontWeight отвечает за визуальную насыщенность, но не заменяет контраст и размер. Для длинного body-текста чрезмерно тяжелое начертание ухудшает сканирование, а слишком легкое может потерять читаемость на небольшом экране. Используйте семантически понятные веса и проверяйте их на реальных строках, а не только на отдельных словах.
LineHeight задает расстояние между строками и особенно важен для многострочного текста. Если он слишком мал, строки визуально сливаются; если слишком велик, абзац распадается на отдельные фрагменты. LetterSpacing помогает настроить плотность набора, но отрицательные значения для обычного текста следует применять осторожно, особенно при малом размере.
Как назначать роли компонентам интерфейса
Компонент должен получать стиль, соответствующий его задаче, а не случайно выбранный размер. Название экрана может использовать headlineSmall, заголовок карточки — titleMedium, описание — bodyMedium, а подпись к статусу — labelMedium. Для кнопки выбирайте labelLarge и учитывайте, что короткая надпись должна оставаться читаемой при увеличении системного шрифта.
Пример для карточки товара: Text(text = product.name, style = MaterialTheme.typography.titleMedium); Text(text = product.description, style = MaterialTheme.typography.bodyMedium); Text(text = product.status, style = MaterialTheme.typography.labelMedium). Такой код явно показывает иерархию и позволяет обновить все карточки изменением одной роли в теме.
Для нестандартного случая используйте копию базовой роли, а не полностью новый стиль с нуля. Например, локально можно применить MaterialTheme.typography.bodyLarge.copy(color = ..., fontWeight = ...). Основные параметры при этом наследуются из темы, и компонент не теряет связь с общей типографической системой.
Локальные стили и наследование текста
Compose позволяет передавать стиль напрямую в Text, но в составных компонентах удобнее использовать локальный контекст текста. ProvideTextStyle помогает задать базовый стиль для дочерних элементов, а LocalTextStyle дает доступ к текущему стилю. Это особенно полезно для компонентов, внутри которых несколько текстовых узлов должны наследовать общие параметры.
Наследование следует применять на ограниченном уровне. Если задать крупный стиль на всем экране, вспомогательные надписи могут неожиданно получить неподходящий размер или межстрочный интервал. Удобнее ограничивать локальную область одним компонентом и явно переопределять роль там, где меняется смысл текста.
Практический алгоритм настройки
- Опишите все типы текста, которые встречаются в интерфейсе: заголовок экрана, заголовок карточки, основной текст, подпись, кнопка и системное сообщение.
- Выберите ближайшие роли Material 3 и не создавайте отдельный стиль для каждого визуального исключения.
- Подключите FontFamily с реальными файлами начертаний и проверьте поддержку кириллицы, латиницы и нужных символов.
- Задайте размеры в sp, согласуйте lineHeight и проверьте переносы на коротких и длинных строках.
- Назначьте роли компонентам через MaterialTheme.typography, а локальные изменения оформляйте через copy().
- Проверьте интерфейс при увеличенном системном размере шрифта, в темной теме и на экранах разной ширины.
- Удалите дублирующиеся локальные TextStyle после того, как базовая тема заработает.
Частые ошибки в типографике Jetpack Compose
Первая ошибка — использование одного body-стиля для всех элементов. Интерфейс становится плоским: заголовок, описание и подпись отличаются только содержанием. Вторая — настройка ролей исключительно по размеру без проверки lineHeight и веса. Визуальная иерархия зависит от сочетания параметров, а не от одного числа.
Третья ошибка — смешивание Material 2 и Material 3 без явной миграционной стратегии. Из-за похожих названий можно получить несовместимые импорты или непредсказуемую тему. Четвертая — подключение только regular-файла при активном использовании Medium и Bold. В таком случае ожидаемое начертание может отсутствовать или выглядеть иначе на разных устройствах.
Пятая ошибка — жестко заданный размер в dp или обрезка текста ради сохранения макета. Доступный интерфейс должен выдерживать масштабирование шрифта и локализацию. Используйте maxLines и overflow только тогда, когда сокращение действительно предусмотрено сценарием, а важные сообщения не прячьте за многоточием.
Чеклист перед выпуском интерфейса
- Определены роли для всех повторяющихся типов текста.
- Основные стили собраны в едином объекте Typography.
- Шрифты содержат необходимые начертания и символы кириллицы.
- Размеры заданы в sp, а межстрочные интервалы проверены на многострочном тексте.
- Заголовки, body-текст и labels имеют заметную, но не чрезмерную иерархию.
- Компоненты корректно выглядят при увеличенном системном размере шрифта.
- Переносы, обрезка и выравнивание проверены на длинных строках.
- Material 2 и Material 3 не смешаны случайно.
- Темная тема и контраст текста проверены отдельно.
FAQ: вопросы о Typography в Compose
Что такое Jetpack Compose Typography?
Jetpack Compose Typography — набор именованных текстовых ролей, объединенных в объект Typography. Он хранит параметры TextStyle для заголовков, основного текста и меток, а MaterialTheme предоставляет эти стили компонентам через единую тему приложения.
Как применить стиль Typography к Text?
Передайте нужную роль в параметр style: например, Text(text = title, style = MaterialTheme.typography.headlineSmall). Такой вызов получает настройки из текущей темы и автоматически отражает изменения, внесенные в объект Typography.
Можно ли использовать собственный шрифт в Material 3?
Да. Создайте FontFamily из файлов шрифта в ресурсах Android и передайте семейство в Typography или отдельный TextStyle. Для предсказуемого результата добавьте реальные файлы тех весов, которые используются в интерфейсе, и проверьте поддержку кириллицы.
Чем отличаются bodyLarge, bodyMedium и bodySmall?
Это три уровня роли для основного текста с разной визуальной плотностью. BodyLarge подходит для заметного содержимого, bodyMedium — для стандартных описаний, а bodySmall — для второстепенной информации. Конкретные значения зависят от конфигурации Typography и могут быть изменены под дизайн-систему.
Нужно ли создавать отдельный стиль для каждой кнопки?
Нет, обычно кнопки используют labelLarge или другую label-роль из темы. Отдельный стиль оправдан, если у продукта есть особая семантическая роль, например компактная кнопка в таблице. В остальных случаях лучше менять цвет, форму и отступы компонента, сохраняя общую текстовую систему.
Почему lineHeight важен для русского текста?
Кириллические строки содержат высокие верхние и нижние элементы букв, поэтому слишком плотный интервал быстро ухудшает чтение. Подбирайте lineHeight на реальных абзацах и проверяйте переносы слов. Одно и то же значение может выглядеть по-разному у разных шрифтов и начертаний.
Как проверить типографику перед публикацией приложения?
Просмотрите ключевые экраны на разных ширинах, при увеличенном системном шрифте, в светлой и темной темах. Проверьте длинные заголовки, многострочные описания, кнопки и сообщения об ошибках. Дополнительно убедитесь, что выбранный шрифт содержит все символы, необходимые для интерфейса и локализации.
Вывод
Typography в Jetpack Compose позволяет превратить разрозненные текстовые параметры в управляемую систему ролей. Определите иерархию, настройте Material 3 Typography, подключите подходящее семейство шрифта и проверьте поведение текста при масштабировании и локализации.
Если приложению нужен индивидуальный визуальный характер, создайте или подберите шрифт для интерфейса на fontgenerator.ru, а затем подключите его к FontFamily и распределите по ролям Compose.