TextField 允许用户输入和修改文本。您可以使用两种类型的文本字段:基于状态的文本字段和基于值的文本字段。选择您要显示内容的类型
我们建议使用基于状态的文本字段,因为它们提供了一种更完整、更可靠的 TextField 状态管理方法。下表概述了这些文本字段类型之间的差异,并包含基于状态的文本字段提供的主要优势
功能 |
基于值的文本字段 |
基于状态的文本字段 |
基于状态的优势 |
|---|---|---|---|
状态管理 |
使用 |
明确使用 |
|
视觉转换 |
使用 |
使用 |
|
行限制 |
接受 |
使用 |
|
安全文本字段 |
不适用 |
|
|
本页面介绍了如何实现 TextField、设置 TextField 输入的样式以及配置其他 TextField 选项,例如键盘选项和视觉转换用户输入。
选择 TextField 实现
TextField 实现有两级
TextField是 Material Design 实现。我们建议您选择此实现,因为它遵循 Material Design 指南BasicTextField允许用户通过硬件或软件键盘编辑文本,但不提供提示或占位符等修饰。
TextField( state = rememberTextFieldState(initialText = "Hello"), label = { Text("Label") } )
OutlinedTextField( state = rememberTextFieldState(), label = { Text("Label") } )
设置 TextField 样式
TextField 和 BasicTextField 共享许多常见的自定义参数。TextField 的完整列表可在 TextField 源代码中找到。这是一个非详尽的有用参数列表
textStylelineLimits
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) )
当您的设计需要 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) )
TextField 内容的彩虹渐变效果。管理文本字段状态
TextField 使用一个名为 TextFieldState 的专用状态持有者类来管理其内容和当前选择。TextFieldState 旨在提升到您架构中适合的任何位置。TextFieldState 提供 2 个主要属性
initialText:TextField的内容。initialSelection:指示光标或选择的当前位置。
TextFieldState 与其他方法(如 onValueChange 回调)的区别在于,TextFieldState 完全封装了整个输入流程。这包括使用正确的后端数据结构、内联过滤器和格式化程序,以及同步来自不同来源的所有编辑。
您可以使用 TextFieldState() 在 TextField 中提升状态。为此,我们建议使用 rememberTextFieldState() 函数。rememberTextFieldState() 在您的可组合项中创建 TextFieldState 实例,确保状态对象被记住,并提供内置的保存和恢复功能
val usernameState = rememberTextFieldState() TextField( state = usernameState, lineLimits = TextFieldLineLimits.SingleLine, placeholder = { Text("Enter Username") } )
rememberTextFieldState 可以有空白参数,也可以传入初始值来表示文本的初始值。如果在后续重组中传入不同的值,则状态的值不会更新。要在初始化后更新状态,请调用 TextFieldState 上的编辑方法。
TextField( state = rememberTextFieldState(initialText = "Username"), lineLimits = TextFieldLineLimits.SingleLine, )
TextField。使用 TextFieldBuffer 修改文本
TextFieldBuffer 用作可编辑文本容器,功能类似于 StringBuilder。它同时包含文本内容和有关当前选择的信息。
您经常会在函数(如 TextFieldState.edit、InputTransformation.transformInput 或 OutputTransformation.transformOutput)中将 TextFieldBuffer 作为接收器范围。在这些函数中,您可以根据需要读取或更新 TextFieldBuffer。之后,这些更改要么提交到 TextFieldState,要么在 OutputTransformation 的情况下传递到渲染管道。
您可以使用标准编辑函数(如 append、insert、replace 或 delete)修改缓冲区内容。要更改选择状态,可以直接设置其 selection: TextRange 变量,或使用实用函数(如 placeCursorAtEnd 或 selectAll)。选择本身由 TextRange 表示,其中起始索引是包含的,结束索引是排他的。起始和结束值相同的 TextRange(例如 (3, 3))表示光标位置,当前没有选择任何字符。
val phoneNumberState = rememberTextFieldState() LaunchedEffect(phoneNumberState) { phoneNumberState.edit { // TextFieldBuffer scope append("123456789") } } TextField( state = phoneNumberState, inputTransformation = InputTransformation { // TextFieldBuffer scope if (asCharSequence().isDigitsOnly()) { revertAllChanges() } }, outputTransformation = OutputTransformation { if (length > 0) insert(0, "(") if (length > 4) insert(4, ")") if (length > 8) insert(8, "-") } )
编辑 TextFieldState 中的文本
有几种方法允许您通过状态变量直接编辑状态
edit:允许您编辑状态内容,并为您提供TextFieldBuffer函数,以便您可以使用insert、replace、append等方法。val usernameState = rememberTextFieldState("I love Android") // textFieldState.text : I love Android // textFieldState.selection: TextRange(14, 14) usernameState.edit { insert(14, "!") } // textFieldState.text : I love Android! // textFieldState.selection: TextRange(15, 15) usernameState.edit { replace(7, 14, "Compose") } // textFieldState.text : I love Compose! // textFieldState.selection: TextRange(15, 15) usernameState.edit { append("!!!") } // textFieldState.text : I love Compose!!!! // textFieldState.selection: TextRange(18, 18) usernameState.edit { selectAll() } // textFieldState.text : I love Compose!!!! // textFieldState.selection: TextRange(0, 18)
setTextAndPlaceCursorAtEnd:清除当前文本,用给定文本替换,并将光标设置在末尾。usernameState.setTextAndPlaceCursorAtEnd("I really love Android") // textFieldState.text : I really love Android // textFieldState.selection : TextRange(21, 21)
clearText:清除所有文本。usernameState.clearText() // textFieldState.text : // textFieldState.selection : TextRange(0, 0)
有关其他 TextFieldState 函数,请参阅 TextFieldState 参考。
修改用户输入
以下部分介绍了如何修改用户输入。输入转换允许您在用户输入时过滤 TextField 输入,而输出转换在用户输入显示在屏幕上之前对其进行格式化。
使用输入转换过滤用户输入
输入转换允许您过滤用户的输入。例如,如果您的 TextField 接收美国电话号码,您只想接受 10 位数字。InputTransformation 的结果保存在 TextFieldState 中。
对于常见的 InputTransformation 用例,有内置的过滤器。要限制长度,请调用 InputTransformation.maxLength()
TextField( state = rememberTextFieldState(), lineLimits = TextFieldLineLimits.SingleLine, inputTransformation = InputTransformation.maxLength(10) )
自定义输入转换
InputTransformation 是一个单一函数接口。实现自定义 InputTransformation 时,您需要重写 TextFieldBuffer.transformInput
class CustomInputTransformation : InputTransformation { override fun TextFieldBuffer.transformInput() { } }
对于电话号码,添加一个自定义输入转换,只允许数字输入到 TextField 中
class DigitOnlyInputTransformation : InputTransformation { override fun TextFieldBuffer.transformInput() { if (!TextUtils.isDigitsOnly(asCharSequence())) { revertAllChanges() } } }
链式输入转换
要在文本输入上添加多个过滤器,请使用 then 扩展函数链式连接 InputTransformation。过滤器按顺序执行。最佳实践是,首先应用最严格的过滤器,以避免对最终将被过滤掉的数据进行不必要的转换。
TextField( state = rememberTextFieldState(), inputTransformation = InputTransformation.maxLength(6) .then(CustomInputTransformation()), )
添加输入转换后,TextField 输入最多接受 10 位数字。
在显示之前格式化输入
OutputTransformation 允许您在用户输入渲染到屏幕上之前对其进行格式化。与 InputTransformation 不同,通过 OutputTransformation 完成的格式化不会保存在 TextFieldState 中。以上一个电话号码示例为例,您需要在适当位置添加括号和破折号
这是处理基于值的 TextField 中 VisualTransformation 的更新方法,主要区别在于您无需计算其偏移映射。
OutputTransformation 是一个单一抽象方法接口。为了实现自定义 OutputTransformation,您需要重写 transformOutput 方法
class CustomOutputTransformation : OutputTransformation { override fun TextFieldBuffer.transformOutput() { } }
要格式化电话号码,请在您的 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, "-") } }
接下来,将您的 OutputTransformation 添加到 TextField
TextField( state = rememberTextFieldState(), outputTransformation = PhoneNumberOutputTransformation() )
转换如何协同工作
下图显示了从文本输入到转换再到输出的流程
- 从输入源接收输入。
- 输入通过
InputTransformation进行过滤,并保存在 TextFieldState 中。 - 输入通过
OutputTransformation进行格式化。 - 输入呈现在
TextField中。
设置键盘选项
TextField 允许您设置键盘配置选项,例如键盘布局,或在键盘支持的情况下启用自动更正。如果软件键盘不符合此处提供的选项,某些选项可能无法保证。以下是支持的键盘选项列表
capitalization(大小写)autoCorrect(自动更正)keyboardType(键盘类型)imeAction(IME 操作)
其他资源
为您推荐
- 注意:禁用 JavaScript 时会显示链接文本
- 构建您的 Compose UI 架构
- 状态与 Jetpack Compose
- 在 Compose 中保存 UI 状态