从像素到灵魂:深入解析字体排印与 Android 字体架构(14):现代 UI 的字体之道:Jetpack Compose 中的实践
本文是「从像素到灵魂:深入解析字体排印与 Android 字体架构」系列的第 14 篇,共 15 篇。在上一篇中,我们探讨了「千挑万选:为你的 App 选择合适的字体」的相关内容。
第三章:现代 UI 的字体之道:Jetpack Compose 中的实践
Jetpack Compose 作为 Android 现代 UI 工具包,提供了声明式的方式来构建界面,其字体处理方式也更加简洁和类型安全。
1. Text Composable 与核心参数
在 Compose 中,androidx.compose.material.Text(或 androidx.compose.foundation.text.BasicText)是显示文本的核心 Composable。字体相关的样式通常直接作为参数传递:
Kotlin
import androidx.compose.material.Text
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import androidx.compose.ui.graphics.Color
@Composable
fun SimpleText() {
Text(
text = "Hello Compose!",
color = Color.Blue,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
fontFamily = FontFamily.Monospace, // 使用系统等宽字体
letterSpacing = 1.sp,
lineHeight = 24.sp
// ... 其他参数如 fontStyle, textAlign, textDecoration
)
}
2. 定义 FontFamily
Compose 提供了灵活的方式来定义字体家族(androidx.compose.ui.text.font.FontFamily):
- 系统字体: FontFamily.Default, FontFamily.SansSerif, FontFamily.Serif, FontFamily.Monospace, FontFamily.Cursive.
- 打包在 res/font 的字体:
- 首先,像之前一样将字体文件(.ttf/.otf)或字体家族 XML 放入 res/font。
- 在代码中创建 FontFamily 对象: Kotlin
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import com.myapp.R // 导入你的 R 文件
// 定义包含多种字重/样式的字体家族
val appFontFamily = FontFamily(
Font(R.font.my_brand_regular, FontWeight.Normal, FontStyle.Normal), // 引用常规体
Font(R.font.my_brand_bold, FontWeight.Bold, FontStyle.Normal), // 引用粗体
Font(R.font.my_brand_italic, FontWeight.Normal, FontStyle.Italic), // 引用斜体
Font(R.font.my_brand_light, FontWeight.Light, FontStyle.Normal) // 引用细体
// ... 可以继续添加其他变体
)
// 定义只包含单个文件的字体
val displayFont = FontFamily(
Font(R.font.my_display_font, FontWeight.Bold) // 默认 FontStyle.Normal
)
// 在 Composable 中使用
Text(text = "Branded Text", fontFamily = appFontFamily, fontWeight = FontWeight.Bold)
Text(text = "Display Heading", fontFamily = displayFont)
- Font() 函数接受资源 ID、可选的 FontWeight 和 FontStyle。Compose 会根据请求的 fontWeight 和 fontStyle 自动选择最匹配的 Font 定义。
- 可下载字体 (Downloadable Fonts via Google Fonts):Compose 提供了专门的 API 来异步加载 Google Fonts。
- 定义 Provider:(通常在 Theme 或 App 级别定义一次) Kotlin
import androidx.compose.ui.text.googlefonts.GoogleFont
import androidx.compose.ui.text.font.FontFamily
import com.myapp.R // 导入你的 R 文件
// 定义 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 // 引用证书数组资源 ID
)
- 定义字体: Kotlin
import androidx.compose.ui.text.googlefonts.Font // 导入 Google Fonts 的 Font
// 定义要下载的字体 (Lato)
val latoFontName = GoogleFont("Lato")
// 创建 FontFamily
val latoFontFamily = FontFamily(
Font(googleFont = latoFontName, fontProvider = provider, weight = FontWeight.Normal),
Font(googleFont = latoFontName, fontProvider = provider, weight = FontWeight.Bold),
Font(googleFont = latoFontName, fontProvider = provider, weight = FontWeight.Light)
)
- 在 Composable 中使用: Kotlin
Text(text = "Downloaded Lato Bold", fontFamily = latoFontFamily, fontWeight = FontWeight.Bold)
Compose 会在后台异步加载字体。在加载完成前,可能会使用备用字体。你也可以使用 androidx.compose.ui.text.font.createFontFamilyResolver(context) 和 resolveAsynchronous 来获得更精细的加载状态控制。
3. Typography in MaterialTheme(Compose 核心实践)
与 View 系统类似,Compose 强烈推荐将文本样式集中定义在主题的 Typography 中。
- 定义 Typography: Kotlin
import androidx.compose.material.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
// (假设 appFontFamily 已如上定义)
val AppTypography = Typography(
h1 = TextStyle(
fontFamily = displayFont, // 使用上面定义的 displayFont
fontWeight = FontWeight.Bold,
fontSize = 96.sp
),
h6 = TextStyle(
fontFamily = appFontFamily,
fontWeight = FontWeight.Medium, // 使用 Medium 字重
fontSize = 20.sp,
letterSpacing = 0.15.sp
),
body1 = TextStyle(
fontFamily = appFontFamily,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp
),
button = TextStyle(
fontFamily = appFontFamily,
fontWeight = FontWeight.Bold, // Button 文本用粗体
fontSize = 14.sp,
letterSpacing = 1.25.sp
)
// ... 定义其他 Material Type Scale 对应的 TextStyle
)
- 在 MaterialTheme 中应用: Kotlin
import androidx.compose.material.MaterialTheme
// ... 其他 imports
@Composable
fun MyAppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colors = if (darkTheme) DarkColorPalette else LightColorPalette
MaterialTheme(
colors = colors,
typography = AppTypography, // 应用我们定义的 Typography
shapes = AppShapes,
content = content
)
}
- 在 Composable 中使用主题样式(推荐): Kotlin
import androidx.compose.material.MaterialTheme
@Composable
fun ThemedText() {
Text(text = "Main Headline", style = MaterialTheme.typography.h1)
Text(text = "Regular body text.", style = MaterialTheme.typography.body1)
Button(onClick = { /*TODO*/ }) {
Text(text = "Click Me", style = MaterialTheme.typography.button) // Button 内部 Text 自动应用
}
}
- 好处: 与 View 系统中的 TextAppearance 类似,提供了极佳的一致性、可维护性和主题化能力。这是 Compose 中处理字体样式的标准且推荐的方式。
Compose 字体小结: Compose 提供了类型安全且灵活的方式来处理字体。优先使用 MaterialTheme 中的 Typography 来定义和应用文本样式。利用 FontFamily 和 Font 定义打包字体,利用 googleFont API 实现可下载字体。
下一篇我们将探讨「包容性设计:无障碍 (Accessibility) 与字体」,敬请关注本系列。
「从像素到灵魂:深入解析字体排印与 Android 字体架构」系列目录
- 万丈高楼平地起:奠定字体排印的坚实基础
- 初识门径:字体的基本分类
- 分小结与展望
- 从曲线到像素——字体渲染管线揭秘
- 无规矩不成方圆——字体授权与合规
- Android 的原生字体生态:Roboto、Noto 与字体回退
- 指令式操作:在代码中动态设置字体
- 个性化表达:打包和使用自定义字体
- 分总结与展望
- 千变万化,始于一文:可变字体 (Variable Fonts)
- 未雨绸缪:字体预加载 (Font Preloading)
- 放眼全球:国际化 (I18N) 与字体再思考
- 千挑万选:为你的 App 选择合适的字体
- 现代 UI 的字体之道:Jetpack Compose 中的实践(本文)
- 包容性设计:无障碍 (Accessibility) 与字体