TextField 允许用户输入和修改文字。您可以使用两种类型的文本字段:基于状态的文本字段和基于值的文本字段。选择要显示哪种类型的内容:
基于状态的文本字段
基于值的文本字段
我们建议使用基于状态的文本字段,因为它们提供了一种更完整、更可靠的方法来管理 TextField 的状态。下表列出了这些类型的文本字段之间的区别,并介绍了基于状态的文本字段的主要优势:
实验性: 基于状态的文本字段依赖于 Material 3 版本 1.4.0-alpha14。
请在问题跟踪器中提交任何 bug。
功能
基于值的文本字段
基于状态的文本字段
基于州/省/自治区/直辖市的福利
状态管理
使用 onValueChange 回调更新文本字段状态。您有责任根据 onValueChange 报告的更改来更新您自己状态中的 value。
明确使用 TextFieldState 对象来管理文本输入状态(值、选择和组合)。此状态可以记住并共享。
移除了 onValueChange 回调,这可防止您引入异步行为。
该状态在重组、配置和进程终止后继续存在。
可视化转换
使用 VisualTransformation 修改显示文本的显示方式。这通常会在一个步骤中处理输入和输出格式。
使用 InputTransformation 在用户输入提交到状态之前对其进行修改,并使用 OutputTransformation 格式化文本字段内容,而无需更改底层状态数据。
您不再需要使用 OutputTransformation 提供原始纯文本与转换后文本之间的偏移量映射。
行数限制
接受 singleLine: Boolean, maxLines: Int 和 minLines: Int 来控制行数。
使用 lineLimits: TextFieldLineLimits 配置文本字段可占用的最少和最多行数。
通过提供 TextFieldLineLimits 类型的 lineLimits 参数,消除了配置行限制时的歧义。
安全文本字段
不适用
SecureTextField 是基于状态的文本字段构建的可组合项,用于写入密码字段。
可让您在后台优化安全性,并附带预定义的 textObfuscationMode 界面。
本页介绍了如何实现 TextField、设置 TextField 输入的样式,以及配置其他 TextField 选项,例如键盘选项和直观地转换用户输入。
选择 TextField 实现
TextField 实现分为两个级别:
TextField 是 Material Design 实现。我们建议您选择此实现,因为它遵循的是 Material Design 指南:
默认样式为填充
OutlinedTextField 是轮廓样式版本
BasicTextField 允许用户使用硬件或软件键盘编辑文本,但没有提供提示或占位符等装饰。
TextField(
state = rememberTextFieldState(initialText = "Hello"),
label = { Text("Label") }
)StateBasedText.kt
OutlinedTextField(
state = rememberTextFieldState(),
label = { Text("Label") }
)StateBasedText.kt
样式 TextField
TextField 和 BasicTextField 共用许多可进行自定义的常用参数。如需查看 TextField 的完整列表,请参阅 TextField 源代码。以下列出了部分有用的参数,但并非详尽无遗:
textStyle
lineLimits
TextField(
state = rememberTextFieldState("Hello\nWorld\nInvisible"),
lineLimits = TextFieldLineLimits.MultiLine(maxHeightInLines = 2),
placeholder = { Text("") },
textStyle = TextStyle(color = Color.Blue, fontWeight = FontWeight.Bold),
label = { Text("Enter text") },
modifier = Modifier.padding(20.dp)
)StateBasedText.kt
如果您的设计调用 Material TextField 或 OutlinedTextField,建议您使用 TextField 而不是 BasicTextField。不过,在构建无需 Material 规范中的装饰的设计时,应使用 BasicTextField。
使用 Brush API 设置输入样式
您可以使用 Brush API 在 TextField 中实现更高级的样式设置。
以下部分介绍了如何使用笔刷向 TextField 输入添加彩色渐变。
如需详细了解如何使用 Brush API 设置文字样式,请参阅使用 Brush API 启用高级样式设置。
使用 TextStyle 实现彩色渐变
如需在 TextField 中实现彩色渐变效果,请将所选画笔设置为 TextField 的 TextStyle。在此示例中,我们使用具有 linearGradient 的内置画笔来查看在 TextField 中输入文本时出现的彩虹渐变效果。
val brush = remember {
Brush.linearGradient(
colors = listOf(Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Magenta)
)
}
TextField(
state = rememberTextFieldState(), textStyle = TextStyle(brush = brush)
)StateBasedText.kt
图 1. TextField内容的彩虹渐变效果。
管理文本字段状态
TextField 使用名为 TextFieldState 的专用状态容器类来存储其内容和选择。TextFieldState 旨在提升到架构中适合的任何位置。TextFieldState 提供以下 2 个主要属性:
initialText:TextField 的内容。
initialSelection:指示光标或所选内容的位置。
TextFieldState 与其他方法(例如 onValueChange 回调)的区别在于,TextFieldState 完全封装了整个输入流。这包括使用正确的后备数据结构、内嵌过滤器和格式化程序,以及同步来自不同来源的所有编辑内容。
注意: 虽然 TextFieldState 属于 Compose Foundation 模块,但它没有界面依赖项,旨在成为强大的状态持有者。TextFieldState 仅使用 Compose 的快照系统提供的数据结构。建议在 ViewModel 中实例化并持有 TextFieldState 实例。
您可以使用 TextFieldState() 在 TextField 中提升状态。为此,我们建议使用 rememberTextFieldState() 函数。rememberTextFieldState() 会在可组合项中创建 TextFieldState 实例,确保状态对象被记住,并提供内置的保存和恢复功能:
val usernameState = rememberTextFieldState()
TextField(
state = usernameState,
lineLimits = TextFieldLineLimits.SingleLine,
placeholder = { Text("Enter Username") }
)StateBasedText.kt
rememberTextFieldState 可以具有空白参数,也可以传入初始值来表示初始化时的文本值。如果在后续的重组中传入不同的值,则状态的值不会更新。如需在初始化后更新状态,请对 TextFieldState 调用编辑方法。
TextField(
state = rememberTextFieldState(initialText = "Username"),
lineLimits = TextFieldLineLimits.SingleLine,
)StateBasedText.kt
图 2. TextField,并将“用户名”作为初始文本。
使用 TextFieldBuffer 修改文字
TextFieldBuffer 用作可编辑的文本框,功能类似于 StringBuilder。它既包含文本内容,也包含有关所选内容的信息。
您经常会遇到 TextFieldBuffer 作为接收器范围出现在 TextFieldState.edit、InputTransformation.transformInput 或 OutputTransformation.transformOutput 等函数中。在这些函数中,您可以根据需要读取或更新 TextFieldBuffer。之后,这些更改会提交到 TextFieldState,或者在 OutputTransformation 的情况下传递到渲染流水线。
您可以使用 append、insert、replace 或 delete 等标准编辑函数来修改缓冲区的内容。如需更改选择状态,您可以直接设置其 selection: TextRange 变量,也可以使用 placeCursorAtEnd 或 selectAll 等实用函数。选择本身由 TextRange 表示,其中起始索引包含在范围内,而结束索引不包含在范围内。具有相同起始值和结束值的 TextRange(例如 (3, 3))表示光标位置未选择任何字符。
val phoneNumberState = rememberTextFieldState("1234567890")
TextField(
state = phoneNumberState,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Phone
),
inputTransformation = InputTransformation.maxLength(10).then {
if (!asCharSequence().isDigitsOnly()) {
revertAllChanges()
}
},
outputTransformation = OutputTransformation {
if (length > 0) insert(0, "(")
if (length > 4) insert(4, ")")
if (length > 8) insert(8, "-")
}
)StateBasedText.kt
修改 TextFieldState 中的文本
您可以通过多种方法直接通过状态变量修改状态:
edit:可让您修改状态内容,并提供 TextFieldBuffer 函数,以便您使用 insert、replace、append 等方法。
// Initial textFieldState text passed in is "I love Android"
// textFieldState.text : I love Android
// textFieldState.selection: TextRange(14, 14)
textFieldState.edit { insert(14, "!") }
// textFieldState.text : I love Android!
// textFieldState.selection: TextRange(15, 15)
textFieldState.edit { replace(7, 14, "Compose") }
// textFieldState.text : I love Compose!
// textFieldState.selection: TextRange(15, 15)
textFieldState.edit { append("!!!") }
// textFieldState.text : I love Compose!!!!
// textFieldState.selection: TextRange(18, 18)
textFieldState.edit { selectAll() }
// textFieldState.text : I love Compose!!!!
// textFieldState.selection: TextRange(0, 18)StateBasedText.kt
setTextAndPlaceCursorAtEnd:清除当前文本,将其替换为指定文本,并将光标设置在末尾。
textFieldState.setTextAndPlaceCursorAtEnd("I really love Android")
// textFieldState.text : I really love Android
// textFieldState.selection : TextRange(21, 21)StateBasedText.kt
clearText:清除所有文本。
textFieldState.clearText()
// textFieldState.text :
// textFieldState.selection : TextRange(0, 0)StateBasedText.kt
如需了解其他 TextFieldState 函数,请参阅 TextFieldState 参考文档。
修改用户输入
以下部分介绍了如何修改用户输入。
借助输入转换,您可以在用户输入时过滤 TextField 输入,而输出转换则会在用户输入显示在屏幕上之前对其进行格式设置。
通过输入转换过滤用户输入
借助输入转换,您可以过滤来自用户的输入内容。例如,如果您的 TextField 接受美国电话号码,您只想接受 10 位数字。InputTransformation 的结果会保存在 TextFieldState 中。
注意: 请勿在 InputTransformation.transformInput() 调用中更改状态。请改用接收器范围 TextFieldBuffer 来修改文本。系统内置了适用于常见 InputTransformation 用例的过滤条件。如需限制长度,请调用 InputTransformation.maxLength():
TextField(
state = rememberTextFieldState(),
lineLimits = TextFieldLineLimits.SingleLine,
inputTransformation = InputTransformation.maxLength(10)
)StateBasedText.kt
自定义输入转换
InputTransformation 是一个单一函数接口。实现自定义 InputTransformation 时,您需要替换 TextFieldBuffer.transformInput:
class CustomInputTransformation : InputTransformation {
override fun TextFieldBuffer.transformInput() {
}
}StateBasedText.kt
对于电话号码,请添加一个自定义输入转换,该转换仅允许在 TextField 中输入数字:
class DigitOnlyInputTransformation : InputTransformation {
override fun TextFieldBuffer.transformInput() {
if (!asCharSequence().isDigitsOnly()) {
revertAllChanges()
}
}
}StateBasedText.kt
链式输入转换
如需对文本输入添加多个过滤条件,请使用 then 扩展函数链接多个 InputTransformation。过滤器按顺序执行。作为最佳实践,请先应用选择性最强的过滤器,以避免对最终会被过滤掉的数据进行不必要的转换。
TextField(
state = rememberTextFieldState(),
inputTransformation = InputTransformation.maxLength(6)
.then(CustomInputTransformation()),
)StateBasedText.kt
添加输入转换后,TextField 输入最多接受 10 位数字。
在显示输入内容之前设置其格式
OutputTransformation 可让您在用户输入内容显示在屏幕上之前对其进行格式设置。与 InputTransformation 不同,通过 OutputTransformation 完成的格式设置不会保存在 TextFieldState 中。在上一个电话号码示例的基础上,您需要在适当的位置添加圆括号和短划线:
图 3. 格式正确的美国电话号码和相应的索引。
这是在基于值的 TextField 中处理 VisualTransformation 的更新方式,主要区别在于您不必计算其偏移量映射。
OutputTransformation 是单一抽象方法接口。为了实现自定义 OutputTransformation,您需要替换 transformOutput 方法:
class CustomOutputTransformation : OutputTransformation {
override fun TextFieldBuffer.transformOutput() {
}
}StateBasedText.kt
如需设置电话号码的格式,请在 OutputTransformation 中添加以下内容:在索引 0 处添加左括号,在索引 4 处添加右括号,在索引 8 处添加短划线:
class PhoneNumberOutputTransformation : OutputTransformation {
override fun TextFieldBuffer.transformOutput() {
if (length > 0) insert(0, "(")
if (length > 4) insert(4, ")")
if (length > 8) insert(8, "-")
}
}StateBasedText.kt
接下来,将 OutputTransformation 添加到 TextField:
TextField(
state = rememberTextFieldState(),
outputTransformation = PhoneNumberOutputTransformation()
)StateBasedText.kt
转换如何协同运作
下图显示了从文本输入到转换再到输出的流程:
图 4. 一张图表,显示了文本输入在转换为文本输出之前所经历的转换。
从输入源接收输入。
输入通过 InputTransformation 进行过滤,然后保存到 TextFieldState 中。
输入通过 OutputTransformation 进行格式设置。
输入内容显示在 TextField 中。
设置键盘选项
借助 TextField,您可以设置键盘配置选项(例如键盘布局),或启用自动更正(如果键盘支持的话)。如果软件键盘不符合此处提供的选项,则无法保证某些选项的可用性。下面列出了支持的键盘选项:
capitalization
autoCorrect
keyboardType
imeAction
其他资源
自动设置文本字段中的电话号码格式
根据用户切换操作显示或隐藏密码
在用户输入时验证输入内容
为您推荐
构建 Compose 界面
状态和 Jetpack Compose
在 Compose 中保存界面状态