5、文本组件:Text 与 TextField 的使用、字体样式、颜色、对齐方式
文本,是任何UI界面最基础的构成元素。不管是显示一段静态文字,还是让用户输入内容,Compose 都提供了非常简洁的 API。今天我们就来聊聊 Text 和 TextField 这两个组件,以及如何控制它们的样式、颜色和对齐方式。
说实话,我刚从传统 View 体系转到 Compose 时,最不习惯的就是文本样式的写法。以前在 XML 里写一堆属性,现在全变成了 Kotlin 代码。但用习惯了你会发现,这种方式其实更灵活,也更符合声明式 UI 的思维。
5.1 Text:显示静态文本
Text 组件,说白了就是用来展示文字的。最简单的用法,一行代码搞定:
@Composable
fun SimpleText() {
Text("Hello, Compose!")
}
但实际项目中,我们很少只用默认样式。你需要控制字体大小、颜色、粗细、行高等等。这些都可以通过 style 参数来设置。
5.1.1 字体样式与颜色
我个人习惯把常用的文本样式封装成常量,方便复用。比如这样:
val titleStyle = TextStyle(
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
color = Color(0xFF1A1A2E),
letterSpacing = 0.5.sp
)
@Composable
fun TitleText(text: String) {
Text(
text = text,
style = titleStyle
)
}
颜色这块,Compose 提供了 Color 类,你可以直接用预定义的颜色,比如 Color.Red、Color.Blue,也可以用 ARGB 或十六进制值。我在项目中遇到过一个问题:用 Color(0xFF000000) 表示黑色,但注意前面两位是透明度,FF 表示完全不透明。如果你写成 0x000000,那就变成全透明了——文字直接消失,排查了半天才发现。
Color(0xFF1A1A2E),编译器会报类型不匹配。正确的写法是 Color(0xFF1A1A2E.toInt()),或者直接用 Color(0xFF1A1A2E) 并确保 Kotlin 版本支持。嗯,这里要注意。
5.1.2 对齐方式
文本对齐,通过 textAlign 参数控制。它接受 TextAlign 枚举值:
Text(
text = "这是一段居中对齐的文字",
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
你可能会问:为什么还要加 Modifier.fillMaxWidth()?因为 Text 默认宽度是包裹内容的,如果不占满父容器,居中对齐的效果就看不出来。我刚开始学 Compose 时就踩过这个坑,文字明明设置了居中,但看起来还是左对齐——其实就是宽度没撑开。
| 对齐方式 | 说明 |
|---|---|
| TextAlign.Start | 起始对齐(LTR 为左,RTL 为右) |
| TextAlign.End | 末尾对齐 |
| TextAlign.Center | 居中对齐 |
| TextAlign.Justify | 两端对齐(多行文本有效) |
5.2 TextField:用户输入文本
TextField 是 Compose 中用于接收用户输入的组件。它分为两种:TextField(Material Design 2 风格)和 OutlinedTextField(带外边框)。我个人更推荐用 OutlinedTextField,视觉上更清晰。
5.2.1 基本用法
TextField 是一个受控组件,你需要维护一个状态变量:
@Composable
fun InputField() {
var text by remember { mutableStateOf("") }
OutlinedTextField(
value = text,
onValueChange = { newText -> text = newText },
label = { Text("请输入内容") },
modifier = Modifier.fillMaxWidth()
)
}
这里用到了 remember 和 mutableStateOf,确保输入框的值在重组时不会丢失。嗯,这是 Compose 状态管理的核心,后面我们会专门讲。
5.2.2 样式与行为控制
TextField 提供了丰富的参数来控制外观和行为。我挑几个常用的说说:
- label:占位提示,输入内容后会浮到上方
- placeholder:占位文本,输入内容后消失
- leadingIcon / trailingIcon:前后图标,比如搜索框前面的放大镜
- visualTransformation:视觉转换,比如密码输入时显示为圆点
- keyboardOptions:键盘类型,比如数字键盘、邮箱键盘
举个例子,一个带密码切换功能的输入框:
@Composable
fun PasswordField() {
var password by remember { mutableStateOf("") }
var showPassword by remember { mutableStateOf(false) }
OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("密码") },
visualTransformation = if (showPassword) VisualTransformation.None
else PasswordVisualTransformation(),
trailingIcon = {
IconButton(onClick = { showPassword = !showPassword }) {
Icon(
imageVector = if (showPassword) Icons.Default.VisibilityOff
else Icons.Default.Visibility,
contentDescription = "切换密码可见"
)
}
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
)
}
我曾经在项目里做过一个登录页面,用户反馈说密码输入时看不到切换按钮。排查后发现是 trailingIcon 的点击区域太小,加了个 Modifier.size(48.dp) 就好了。嗯,交互细节真的很重要。
5.3 字体资源的加载
如果你需要使用自定义字体,Compose 也支持。把字体文件放到 res/font/ 目录下,然后这样加载:
val customFontFamily = FontFamily(
Font(R.font.pingfang_regular, FontWeight.Normal),
Font(R.font.pingfang_bold, FontWeight.Bold)
)
Text(
text = "自定义字体",
fontFamily = customFontFamily,
fontWeight = FontWeight.Bold
)
我个人建议,如果项目中有多种字体粗细,最好把整个 FontFamily 定义好,而不是每个地方单独加载。这样统一管理,后期换字体也方便。
5.4 知识体系总览
下面这张图,帮你梳理本章的核心内容:
5.5 避坑指南
最后,分享几个我实际项目中遇到的坑:
- Text 不显示:检查颜色是否设置了透明度,或者父容器大小是否为0。我曾经把 Text 放在一个高度为0的 Box 里,找了半天原因。
- TextField 输入卡顿:如果输入框内容很多,考虑用
TextFieldValue替代 String,它可以更精细地控制光标位置和选择范围。 - 字体文件不生效:确认字体文件放在
res/font/目录下,并且文件名是小写字母和下划线。Compose 对资源文件名有严格限制。
文本组件看似简单,但用好它们,能让你的 UI 体验提升一个档次。记住一点:样式统一、状态可控、交互清晰。做到这三点,你的文本组件就不会出大问题。
核心要点回顾:
- Text 通过
style参数控制字体、颜色、对齐 - TextField 是受控组件,必须用
remember+mutableStateOf管理状态 - 自定义字体通过
FontFamily加载,统一管理更佳 - 对齐效果需要配合
Modifier.fillMaxWidth()才能正确显示
公众号:蓝海资料掘金营,微信deep3321