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

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

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

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

@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.7.5"
    }

    Котлин

    dependencies {
        ...
        implementation("androidx.compose.ui:ui-text-google-fonts:1.7.5")
    }
  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:

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 Knowledge , полном каталоге доступных переменных шрифтов и таблице поддерживаемых осей для каждого шрифта.

В этом документе показано, как реализовать переменный шрифт в вашем приложении 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. Теперь, когда вы определили свою типографику, передайте ее в M3 MaterialTheme :

    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 настраивается с помощью стиля темы материала и содержит различную конфигурацию изменяемого шрифта. Вы можете использовать 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. Текст, показывающий пользовательские оси, установленные в переменных шрифтах.

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

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

{% дословно %} {% дословно %} {% дословно %} {% дословно %}