Работа со шрифтами

На этой странице описано, как установить шрифты в приложении Compose.

Установить шрифт

Text есть параметр fontFamily , позволяющий задать шрифт, используемый в создаваемом элементе. По умолчанию включены семейства шрифтов serif, sans-serif, monospace и cursive:

@Composable
fun DifferentFonts() {
    Column {
        Text("Hello World", fontFamily = FontFamily.Serif)
        Text("Hello World", fontFamily = FontFamily.SansSerif)
    }
}

Слова

Атрибут fontFamily позволяет работать с пользовательскими шрифтами и гарнитурами, определенными в папке res/font :

Графическое отображение папки res > font в среде разработки.

В этом примере показано, как определить fontFamily на основе этих файлов шрифтов, используя функцию Font :

val firaSansFamily = FontFamily(
    Font(R.font.firasans_light, FontWeight.Light),
    Font(R.font.firasans_regular, FontWeight.Normal),
    Font(R.font.firasans_italic, FontWeight.Normal, FontStyle.Italic),
    Font(R.font.firasans_medium, FontWeight.Medium),
    Font(R.font.firasans_bold, FontWeight.Bold)
)

Вы можете передать этот fontFamily в ваш компонент Text . Поскольку fontFamily может включать разные варианты толщины, вы можете вручную установить fontWeight , чтобы выбрать правильную толщину для вашего текста:

Column {
    Text(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Light)
    Text(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Normal)
    Text(
        text = "text",
        fontFamily = firaSansFamily,
        fontWeight = FontWeight.Normal,
        fontStyle = FontStyle.Italic
    )
    Text(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Medium)
    Text(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Bold)
}

Слова

Чтобы узнать, как настроить типографику во всем приложении, см. раздел «Пользовательские системы дизайна в Compose» .

Шрифты, доступные для скачивания

Начиная с версии Compose 1.2.0 , вы можете использовать API загружаемых шрифтов в своем приложении Compose для асинхронной загрузки шрифтов Google и их использования в приложении.

Поддержка загружаемых шрифтов, предоставляемых собственными разработчиками, в настоящее время недоступна.

Используйте загружаемые шрифты программным способом.

Чтобы загрузить шрифт программным способом из вашего приложения, выполните следующие шаги:

  1. Добавьте зависимость:

    Классный

    dependencies {
        ...
        implementation "androidx.compose.ui:ui-text-google-fonts:1.10.1"
    }

    Котлин

    dependencies {
        ...
        implementation("androidx.compose.ui:ui-text-google-fonts:1.10.1")
    }
  2. Инициализируйте объект GoogleFont.Provider , указав учетные данные для Google Fonts:
    val provider = GoogleFont.Provider(
        providerAuthority = "com.google.android.gms.fonts",
        providerPackage = "com.google.android.gms",
        certificates = R.array.com_google_android_gms_fonts_certs
    )
    Поставщик получает следующие параметры:
    • Авторитетный поставщик шрифтов для Google Fonts.
    • Пакет поставщика шрифтов для проверки подлинности поставщика.
    • Список наборов хешей для сертификатов, используемых для проверки подлинности поставщика. Необходимые хеши для поставщика Google Fonts можно найти в файле font_certs.xml в демонстрационном приложении Jetchat.
  3. Определите семейство FontFamily :
    // ...
     import androidx.compose.ui.text.googlefonts.GoogleFont
     import androidx.compose.ui.text.font.FontFamily
     import androidx.compose.ui.text.googlefonts.Font
     // ...
    
    val fontName = GoogleFont("Lobster Two")
    
    val fontFamily = FontFamily(
        Font(googleFont = fontName, fontProvider = provider)
    )
    Вы можете запросить другие параметры шрифта, такие как толщина и стиль, с помощью FontWeight и FontStyle соответственно:
    // ...
     import androidx.compose.ui.text.googlefonts.GoogleFont
     import androidx.compose.ui.text.font.FontFamily
     import androidx.compose.ui.text.googlefonts.Font
     // ...
    
    val fontName = GoogleFont("Lobster Two")
    
    val fontFamily = FontFamily(
        Font(
            googleFont = fontName,
            fontProvider = provider,
            weight = FontWeight.Bold,
            style = FontStyle.Italic
        )
    )
  4. Настройте FontFamily , который будет использоваться в вашей текстовой функции:

Text(
    fontFamily = fontFamily, text = "Hello World!"
)

Вы также можете задать типографику для использования вашего FontFamily :

val MyTypography = Typography(
    bodyMedium = TextStyle(
        fontFamily = fontFamily, fontWeight = FontWeight.Normal, fontSize = 12.sp/*...*/
    ),
    bodyLarge = TextStyle(
        fontFamily = fontFamily,
        fontWeight = FontWeight.Bold,
        letterSpacing = 2.sp,
        /*...*/
    ),
    headlineMedium = TextStyle(
        fontFamily = fontFamily, fontWeight = FontWeight.SemiBold/*...*/
    ),
    /*...*/
)

Далее установите типографику в соответствии с темой вашего приложения:

MyAppTheme(
    typography = MyTypography
)/*...*/

Пример приложения, в котором реализована возможность загрузки шрифтов в Compose совместно с Material3 , можно посмотреть в демонстрационном приложении Jetchat .

Добавить резервные шрифты

Вы можете задать цепочку резервных вариантов для вашего шрифта на случай, если его загрузка не удастся выполнить должным образом. Например, если ваш загружаемый шрифт определен следующим образом:

// ...
 import androidx.compose.ui.text.googlefonts.Font
 // ...

val fontName = GoogleFont("Lobster Two")

val fontFamily = FontFamily(
    Font(googleFont = fontName, fontProvider = provider),
    Font(googleFont = fontName, fontProvider = provider, weight = FontWeight.Bold)
)

Вы можете задать значения по умолчанию для вашего шрифта для обоих вариантов толщины следующим образом:

// ...
 import androidx.compose.ui.text.font.Font
 import androidx.compose.ui.text.googlefonts.Font
 // ...

val fontName = GoogleFont("Lobster Two")

val fontFamily = FontFamily(
    Font(googleFont = fontName, fontProvider = provider),
    Font(resId = R.font.my_font_regular),
    Font(googleFont = fontName, fontProvider = provider, weight = FontWeight.Bold),
    Font(resId = R.font.my_font_regular_bold, weight = FontWeight.Bold)
)

Убедитесь, что вы добавляете правильные импорты.

Определение FontFamily таким образом создает FontFamily , содержащий две цепочки, по одной для каждого варианта толщины шрифта. Механизм загрузки сначала попытается найти шрифт из интернета, а затем шрифт, расположенный в локальной папке ресурсов R.font .

Отладьте свою реализацию.

Чтобы проверить правильность загрузки шрифта, вы можете определить обработчик отладочной сопрограммы. Ваш обработчик определяет, что делать в случае, если шрифт не загружается асинхронно.

Для начала создайте обработчик CoroutineExceptionHandler :

val handler = CoroutineExceptionHandler { _, throwable ->
    // process the Throwable
    Log.e(TAG, "There has been an issue: ", throwable)
}

Передайте его методу createFontFamilyResolver , чтобы обработчик использовал новый обработчик:

CompositionLocalProvider(
    LocalFontFamilyResolver provides createFontFamilyResolver(LocalContext.current, handler)
) {
    Column {
        Text(
            text = "Hello World!", style = MaterialTheme.typography.bodyMedium
        )
    }
}

Вы также можете использовать API isAvailableOnDevice от поставщика услуг, чтобы проверить, доступен ли поставщик и правильно ли настроены сертификаты. Для этого вы можете вызвать метод isAvailableOnDevice , который возвращает false, если поставщик настроен неправильно.

val context = LocalContext.current
LaunchedEffect(Unit) {
    if (provider.isAvailableOnDevice(context)) {
        Log.d(TAG, "Success!")
    }
}

Предостережения

Google Fonts требуется несколько месяцев, чтобы сделать новые шрифты доступными для Android. Между добавлением шрифта на fonts.google.com и его доступностью через API загрузки шрифтов (в системе View или в Compose) существует временной промежуток. Вновь добавленные шрифты могут не загрузиться в вашем приложении с ошибкой IllegalStateException . Чтобы помочь разработчикам отличить эту ошибку от других типов ошибок загрузки шрифтов, мы добавили описательное сообщение об исключении в Compose , изменения в котором можно посмотреть здесь . Если вы обнаружите какие-либо проблемы, сообщите о них , используя систему отслеживания ошибок .

Используйте переменные шрифты

Вариативный шрифт — это формат шрифта, позволяющий одному файлу шрифта содержать различные стили. С помощью вариативных шрифтов можно изменять оси (или параметры) для создания желаемого стиля. Эти оси могут быть стандартными, такими как толщина, ширина, наклон и курсив, или пользовательскими, которые различаются в зависимости от вариативного шрифта.

Пять вариантов конфигурации одного и того же шрифта с переменными значениями, но с разными значениями по осям.
Рисунок 1. Текст, использующий один и тот же вариативный шрифт, настроенный с помощью различных значений осей.

Использование вариативных шрифтов вместо обычных файлов шрифтов позволяет иметь только один файл шрифта вместо нескольких.

Для получения более подробной информации о вариативных шрифтах см. раздел «Знания Google Fonts» , полный каталог доступных вариативных шрифтов и таблицу поддерживаемых осей для каждого шрифта.

В этом документе показано, как реализовать переменный шрифт в вашем приложении Compose.

Загрузить переменный шрифт

  1. Загрузите нужный вам вариативный шрифт (например , Roboto Flex ) и поместите его в папку app/res/font вашего приложения. Убедитесь, что добавляемый файл ttf содержит именно вариативный шрифт , а имя файла шрифта написано строчными буквами и не содержит специальных символов.

  2. Чтобы загрузить шрифт с изменяемым значением, определите FontFamily используя шрифт, находящийся в каталоге res/font/ :

    // In Typography.kt
    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily =
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(950),
                    FontVariation.width(30f),
                    FontVariation.slant(-6f),
                )
            )
        )

    API FontVariation позволяет настраивать стандартные параметры шрифта, такие как толщина , ширина и наклон . Это стандартные параметры, доступные для любого вариативного шрифта. Вы можете создавать различные конфигурации шрифта в зависимости от того, где он будет использоваться.

  3. Вариативные шрифты доступны только в версиях Android O и выше, поэтому добавьте защитный механизм и настройте соответствующий резервный вариант:

    // In Typography.kt
    val default = FontFamily(
        /*
        * This can be any font that makes sense
        */
        Font(
            R.font.robotoflex_static_regular
        )
    )
    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(950),
                    FontVariation.width(30f),
                    FontVariation.slant(-6f),
                )
            )
        )
    } else {
        default
    }

  4. Для удобства повторного использования выделите настройки в набор констант и замените настройки шрифта следующими константами:

    // VariableFontDimension.kt
    object DisplayLargeVFConfig {
        const val WEIGHT = 950
        const val WIDTH = 30f
        const val SLANT = -6f
        const val ASCENDER_HEIGHT = 800f
        const val COUNTER_WIDTH = 500
    }
    
    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(DisplayLargeVFConfig.WEIGHT),
                    FontVariation.width(DisplayLargeVFConfig.WIDTH),
                    FontVariation.slant(DisplayLargeVFConfig.SLANT),
                )
            )
        )
    } else {
        default
    }

  5. Настройте типографику Material Design 3 для использования FontFamily :

    // Type.kt
    val Typography = Typography(
        displayLarge = TextStyle(
            fontFamily = displayLargeFontFamily,
            fontSize = 50.sp,
            lineHeight = 64.sp,
            letterSpacing = 0.sp,
            /***/
        )
    )

    В этом примере используется шрифт displayLarge из Material 3 , который имеет другие настройки по умолчанию и рекомендуемое применение. Например, displayLarge следует использовать для короткого, важного текста, поскольку это самый крупный текст на экране.

    В Material 3 вы можете изменять значения по умолчанию для TextStyle и fontFamily , чтобы настроить типографику. В приведенном выше фрагменте кода вы настраиваете экземпляры TextStyle для персонализации параметров шрифта для каждого семейства шрифтов.

  6. Теперь, когда вы определили типографику, передайте её в MaterialTheme M3:

    MaterialTheme(
        colorScheme = MaterialTheme.colorScheme,
        typography = Typography,
        content = content
    )

  7. Наконец, используйте составной Text элемент и укажите стиль одного из определенных стилей типографики, например, MaterialTheme.typography.displayLarge :

    @Composable
    @Preview
    fun CardDetails() {
        MyCustomTheme {
            Card(
                shape = RoundedCornerShape(8.dp),
                elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(16.dp)
            ) {
                Column(
                    modifier = Modifier.padding(16.dp)
                ) {
                    Text(
                        text = "Compose",
                        style = MaterialTheme.typography.displayLarge,
                        modifier = Modifier.padding(bottom = 8.dp),
                        maxLines = 1
                    )
                    Text(
                        text = "Beautiful UIs on Android",
                        style = MaterialTheme.typography.headlineMedium,
                        modifier = Modifier.padding(bottom = 8.dp),
                        maxLines = 2
                    )
                    Text(
                        text = "Jetpack Compose is Android’s recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.",
                        style = MaterialTheme.typography.bodyLarge,
                        modifier = Modifier.padding(bottom = 8.dp),
                        maxLines = 3
                    )
                }
            }
        }
    }

    Каждый Text компонент настраивается через стиль своей темы Material и содержит различные параметры шрифта. Вы можете использовать MaterialTheme.typography для получения типографики, предоставленной компоненту M3 MaterialTheme .

Три разных текста, в каждом из которых представлены различные варианты шрифта.
Рисунок 2. Изменение шрифта, применяемое в трех различных конфигурациях.

Используйте пользовательские оси

Шрифты также могут иметь пользовательские оси. Они определяются в самом файле шрифта. Например, шрифт Roboto Flex имеет ось высоты верхних выносных элементов ( "YTAS" ), которая регулирует высоту верхних выносных элементов строчных букв, а ось ширины внутреннего пространства ( "XTRA" ) регулирует ширину каждой буквы.

Вы можете изменить значения этих осей с помощью настроек FontVariation .

Для получения более подробной информации о настраиваемых осях для шрифта см. таблицу поддерживаемых осей для каждого шрифта.

  1. Для использования пользовательских осей определите функции для пользовательских осей ascenderHeight и counterWidth :

    fun ascenderHeight(ascenderHeight: Float): FontVariation.Setting {
        require(ascenderHeight in 649f..854f) { "'Ascender Height' must be in 649f..854f" }
        return FontVariation.Setting("YTAS", ascenderHeight)
    }
    
    fun counterWidth(counterWidth: Int): FontVariation.Setting {
        require(counterWidth in 323..603) { "'Counter width' must be in 323..603" }
        return FontVariation.Setting("XTRA", counterWidth.toFloat())
    }

    Эти функции выполняют следующие действия:

    • Определите ограничения для значений, которые они могут принимать. Как вы можете видеть в каталоге переменных шрифтов , ascenderHeight (YTAS) имеет минимальное значение 649f и максимальное значение 854f .
    • Возвращает настройки шрифта, чтобы конфигурация была готова к добавлению в шрифт. В методе FontVariation.Setting() имя оси ( YTAS, XTRA ) задано жестко, и в качестве параметра принимается значение.
  2. Используя оси с конфигурацией шрифта, передайте дополнительные параметры каждому загруженному Font :

    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(DisplayLargeVFConfig.WEIGHT),
                    FontVariation.width(DisplayLargeVFConfig.WIDTH),
                    FontVariation.slant(DisplayLargeVFConfig.SLANT),
                    ascenderHeight(DisplayLargeVFConfig.ASCENDER_HEIGHT),
                    counterWidth(DisplayLargeVFConfig.COUNTER_WIDTH)
                )
            )
        )
    } else {
        default
    }

    Обратите внимание, что высота верхних выносных элементов строчных букв теперь увеличена, а остальной текст стал шире:

Три разных текста, демонстрирующих различные конфигурации вариативных шрифтов с заданными пользовательскими осями — у некоторых выносные элементы строчных букв расположены выше, а ширина шрифта больше, чем раньше.
Рисунок 3. Текст, демонстрирующий пользовательские оси, заданные для переменных шрифтов.

Дополнительные ресурсы

Для получения более подробной информации ознакомьтесь со следующей записью в блоге о вариативных шрифтах:

{% verbatim %} {% endverbatim %} {% verbatim %} {% endverbatim %}