此页面介绍如何在 Compose 应用中设置字体。
设置字体
Text
有一个 fontFamily
参数,允许设置在组合项中使用的字体。默认情况下,衬线、无衬线、等宽和草书字体系列已包含
@Composable fun DifferentFonts() { Column { Text("Hello World", fontFamily = FontFamily.Serif) Text("Hello World", fontFamily = FontFamily.SansSerif) } }
您可以使用 fontFamily
属性来处理在 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 字体 并将其用于您的应用。
目前尚不支持自定义提供程序提供的可下载字体。
以编程方式使用可下载字体
要在应用中以编程方式下载字体,请按照以下步骤操作
- 添加依赖项
Groovy
dependencies { ... implementation "androidx.compose.ui:ui-text-google-fonts:1.7.5" }
Kotlin
dependencies { ... implementation("androidx.compose.ui:ui-text-google-fonts:1.7.5") }
- 使用 Google 字体的凭据初始化
GoogleFont.Provider
提供程序接收的参数为: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 字体的字体提供程序权限。
- 用于验证提供程序身份的字体提供程序包。
- 用于验证提供程序身份的证书的散列集列表。您可以在 Jetchat 示例应用中找到 Google 字体提供程序所需的散列在
font_certs.xml
文件中。
- 定义一个
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 ) )
- 配置要在 Text 组合函数中使用的
FontFamily
Text( fontFamily = fontFamily, text = "Hello World!" )
您还可以定义 Typography 来使用您的 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 ) } }
您还可以使用提供程序中的 isAvailableOnDevice
API 来测试提供程序是否可用以及证书是否已正确配置。为此,您可以调用返回 false(如果提供程序配置不正确)的 isAvailableOnDevice
方法。
val context = LocalContext.current LaunchedEffect(Unit) { if (provider.isAvailableOnDevice(context)) { Log.d(TAG, "Success!") } }
注意事项
Google 字体需要数月时间才能在 Android 上提供新字体。在 fonts.google.com 中添加字体与通过可下载字体 API(在 View 系统或 Compose 中)提供字体之间存在时间差。新添加的字体可能会在您的应用中因 IllegalStateException
而加载失败。为了帮助开发者将此错误与其他类型的字体加载错误区分开来,我们在 Compose 中添加了此异常的描述性消息此处进行了更改。如果您发现任何问题,请使用问题跟踪器报告。
使用可变字体
可变字体是一种字体格式,允许一个字体文件包含不同的样式。使用可变字体,您可以修改轴(或参数)以生成您喜欢的样式。这些轴可以是标准的,例如粗细、宽度、倾斜和斜体,也可以是自定义的,这在不同的可变字体中有所不同。
使用可变字体而不是常规字体文件,您可以只使用一个字体文件而不是多个文件。
有关可变字体的更多背景信息,请参阅 Google 字体知识、可用可变字体的完整目录以及每种字体的支持轴的表格。
本文档将向您展示如何在 Compose 应用中实现可变字体。
加载可变字体
下载您要使用的可变字体(例如 Roboto Flex),并将其放在应用中的
app/res/font
文件夹中。确保您添加的 .ttf
文件是字体的可变字体版本,并且字体文件名全部小写,并且不包含任何特殊字符。要加载可变字体,请使用放在
res/font/
目录中的字体定义FontFamily
// 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 允许您配置标准字体轴,例如 粗细、宽度和 倾斜。这些是任何可变字体都可用的标准轴。您可以根据字体的使用位置创建字体的不同配置。可变字体仅适用于 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 }
将设置提取到一组常量中,以便于重用,并用这些常量替换字体设置
// 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 }
配置 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
的实例以自定义每个字体的字体设置。现在您已定义了排版,将其传递给 M3
MaterialTheme
MaterialTheme( colorScheme = MaterialTheme.colorScheme, typography = Typography, content = content )
最后,使用
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
来检索提供给 M3MaterialTheme
组合项的排版。
使用自定义轴
字体也可以具有自定义轴。这些是在字体文件本身中定义的。例如,Roboto Flex 字体具有上行高度("YTAS"
)轴,它调整小写上行的高度,而计数器宽度("XTRA"
)调整每个字母的宽度。
您可以使用 FontVariation
设置更改这些轴的值。
有关您可以为字体配置的自定义轴的更多信息,请参阅每种字体的支持轴的表格。
要使用自定义轴,请为自定义
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
)是硬编码的,它将值作为参数。
- 定义它们可以接受的值的防护栏。正如您在可变字体目录中看到的那样,
使用带有字体配置的轴,将其他参数传递给加载的每个
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 }
请注意,小写上行的高度现在已增加,其他文本也更宽了
其他资源
有关更多信息,请参阅以下关于可变字体的博文:
为您推荐
- 注意:禁用 JavaScript 时将显示链接文本
- Compose 中的资源
- 设置文本样式
- Compose 中的 Material Design 2