使用字体

本页介绍了如何在 Compose 应用中设置字体。

设置字体

Text 有一个 fontFamily 参数,用于设置可组合项中使用的字体。默认情况下,系统会添加 Serif、Sans Serif、等宽和 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、 可以使用 Compose 应用中的可下载字体 API 下载 Google 异步字体,并在您的应用中使用这些字体。

目前尚不支持自定义提供程序提供的可下载字体。

以程序化方式使用可下载字体

如需从您的应用内以编程方式下载字体,请按以下步骤操作:

  1. 添加依赖项:

    Groovy

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

    Kotlin

    dependencies {
        ...
        implementation("androidx.compose.ui:ui-text-google-fonts:1.6.8")
    }
  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)
    )
    您可以使用 FontWeightFontStyle 分别为:
    // ...
     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(
    labelMedium = TextStyle(
        fontFamily = fontFamily, fontWeight = FontWeight.Normal, fontSize = 12.sp/*...*/
    ),
    labelLarge = TextStyle(
        fontFamily = fontFamily,
        fontWeight = FontWeight.Bold,
        letterSpacing = 2.sp,
        /*...*/
    ),
    displayMedium = TextStyle(
        fontFamily = fontFamily, fontWeight = FontWeight.SemiBold/*...*/
    ),
    /*...*/
)

接下来,将 Typography 设为应用的主题:

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
        )
    }
}

您还可以使用相应提供程序提供的 isAvailableOnDevice API 来测试提供程序是否可用以及证书是否正确配置。为此,您可以调用 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),
                )
            )
        )

    借助 FontVariation API,您可以配置标准字体轴,例如 权重宽度倾斜度。这些是标准轴 支持任意可变字体您可以创建不同的 确定使用相应字体的位置。

  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 可组合项都通过其 Material 主题的样式和 包含不同的可变字体配置。您可以使用 MaterialTheme.typography,用于检索提供给 M3 的排版 MaterialTheme 可组合项。

三种不同的文字,均展示不同的字体配置。
图 2. 在三种不同的配置中应用了可变字体。

使用自定义轴

字体也可以有自定义轴。这些是在字体文件本身中定义的。 例如,Roboto Flex 字体具有上出高度 ("YTAS") 轴, 用于调整小写上升标的高度,同时调整计数器宽度 ("XTRA") 调整每个字母的宽度。

您可以使用 FontVariation 设置更改这些轴的值。

如需详细了解您可以为字体配置的自定义轴,请参阅 支持的轴表格

  1. 如需使用自定义轴,请为自定义 ascenderHeightcounterWidth 轴:

    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.此文本显示了在可变字体上设置的自定义轴。

其他资源

如需了解详情,请参阅以下有关可变字体的博文: