Jetpack Composes 之 TextField 详解
- 2022 年 6 月 05 日
本文字数:5741 字
阅读完需:约 19 分钟
TextField
@Composablefun TextField( value: String, onValueChange: (String) -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, readOnly: Boolean = false, textStyle: TextStyle = LocalTextStyle.current, label: @Composable (() -> Unit)? = null, placeholder: @Composable (() -> Unit)? = null, leadingIcon: @Composable (() -> Unit)? = null, trailingIcon: @Composable (() -> Unit)? = null, isError: Boolean = false, visualTransformation: VisualTransformation = VisualTransformation.None, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, keyboardActions: KeyboardActions = KeyboardActions(), singleLine: Boolean = false, maxLines: Int = Int.MAX_VALUE, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, shape: Shape = MaterialTheme.shapes.small. (bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize), colors: TextFieldColors = TextFieldDefaults.textFieldColors())
Material Design filled text field
Filled TextField 比 Outlined TextField 有更多的视觉效果,可以让它们在被其他内容和组件包围时显得更加突出。
注意
Filled TextField 和 Outlined TextField 都是按照 Material Design 来设计的,所以里面的一些间距是固定的,当你使用 Modifier.size() 等之类的方法尝试去修改它很可能会有以下的效果
TextField( value = text, onValueChange = { text = it }, modifier = Modifier.height(20.dp))
如果你想自定义一个 TextField 的高度,以及其他的自定义效果,你应该使用 BasicTextField
一个简单的 TextField 使用的例子是这样的:
import androidx.compose.runtime.*
@Composablefun TextFieldDemo() { var text by remember{ mutableStateOf("")}
TextField( value = text, onValueChange = { text = it } )}
1. singleLine 参数
使用 singleLine 参数可以将 TextField 设置成只有一行
设置了 singleLine 再设置 maxLines 将无效
@Composablefun TextFieldDemo() { var text by remember{ mutableStateOf("")}
TextField( value = text, onValueChange = { text = it }, singleLine = true )}
2. label 参数
label 标签可以运用在 TextField 中,当聚焦的时候会改变字体大小
@Composablefun TextFieldDemo() { var text by remember{ mutableStateOf("")}
Column( modifier = Modifier .fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { TextField( value = text, onValueChange = { text = it }, singleLine = true, label = { Text("邮箱") } ) }}
3. leadingIcon 参数
leadingIcon 参数可以在 TextField 前面布置 lambda 表达式所接收到的东西
TextField( value = text, onValueChange = { text = it }, leadingIcon = { Icon(Icons.Filled.Search, null) },)
虽然名字上叫做 leadingIcon,但是 leadingIcon 接收来自一个 @Composable 函数的 lambda 表达式,
我们也可以在里面填入 Text 函数
TextField( value = text, onValueChange = { text = it }, leadingIcon = { Text("联系人") },)
4. trailingIcon 参数
trailingIcon 参数可以在 TextField 尾部布置 lambda 表达式所接收到的东西
TextField( value = text, onValueChange = { text = it }, trailingIcon = { Text("@163.com") },)
trailingIcon = { IconButton(onClick = { }){ Icon(Icons.Filled.Send, null) }},
5. Color 参数
@Composablefun textFieldColors( // 输入的文字颜色 textColor: Color = LocalContentColor.current. (LocalContentAlpha.current),
// 禁用 TextField 时,已有的文字颜色 disabledTextColor: Color = textColor. (ContentAlpha.disabled),
// 输入框的背景颜色,当设置为 Color.Transparent 时,将透明 backgroundColor: Color = MaterialTheme.colors.onSurface. (alpha = BackgroundOpacity),
// 输入框的光标颜色 cursorColor: Color = MaterialTheme.colors.primary,
// 当 TextField 的 isError 参数为 true 时,光标的颜色 errorCursorColor: Color = MaterialTheme.colors.error,
// 当输入框处于焦点时,底部指示器的颜色 focusedIndicatorColor: Color = MaterialTheme.colors.primary. (alpha = ContentAlpha.high),
// 当输入框不处于焦点时,底部指示器的颜色 unfocusedIndicatorColor: Color = MaterialTheme.colors.onSurface. (alpha = UnfocusedIndicatorLineOpacity),
// 禁用 TextField 时,底部指示器的颜色 disabledIndicatorColor: Color = unfocusedIndicatorColor. (alpha = ContentAlpha.disabled),
// 当 TextField 的 isError 参数为 true 时,底部指示器的颜色 errorIndicatorColor: Color = MaterialTheme.colors.error,
// TextField 输入框前头的颜色 leadingIconColor: Color = MaterialTheme.colors.onSurface. (alpha = IconOpacity),
// 禁用 TextField 时 TextField 输入框前头的颜色 disabledLeadingIconColor: Color = leadingIconColor. (alpha = ContentAlpha.disabled),
// 当 TextField 的 isError 参数为 true 时 TextField 输入框前头的颜色 errorLeadingIconColor: Color = leadingIconColor,
// TextField 输入框尾部的颜色 trailingIconColor: Color = MaterialTheme.colors.onSurface. (alpha = IconOpacity),
// 禁用 TextField 时 TextField 输入框尾部的颜色 disabledTrailingIconColor: Color = trailingIconColor. (alpha = ContentAlpha.disabled),
// 当 TextField 的 isError 参数为 true 时 TextField 输入框尾部的颜色 errorTrailingIconColor: Color = MaterialTheme.colors.error,
// 当输入框处于焦点时,Label 的颜色 focusedLabelColor: Color = MaterialTheme.colors.primary. (alpha = ContentAlpha.high),
// 当输入框不处于焦点时,Label 的颜色 unfocusedLabelColor: Color = MaterialTheme.colors.onSurface. (ContentAlpha.medium),
// 禁用 TextField 时,Label 的颜色 disabledLabelColor: Color = unfocusedLabelColor. (ContentAlpha.disabled),
// 当 TextField 的 isError 参数为 true 时,Label 的颜色 errorLabelColor: Color = MaterialTheme.colors.error,
// Placeholder 的颜色 placeholderColor: Color = MaterialTheme.colors.onSurface. (ContentAlpha.medium),
// 禁用 TextField 时,placeholder 的颜色 disabledPlaceholderColor: Color = placeholderColor. (ContentAlpha.disabled))
调用方法
TextField( value = text, onValueChange = { text = it }, leadingIcon = { Icon(Icons.Filled.Search, null) }, colors = TextFieldDefaults.textFieldColors( textColor = Color(0xFF0079D3), backgroundColor = Color.Transparent ))
在你使用 IDE 智能补全的时候可能遇到这种情况
解决方法如下,手动打完函数名
6. visualTransformation 参数
visualTransformation 可以帮助我们应用输入框的显示模式
var text by remember{mutableStateOf("")}var passwordHidden by remember{ mutableStateOf(false)}
TextField( value = text, onValueChange = { text = it }, trailingIcon = { IconButton( onClick = { passwordHidden = !passwordHidden } ){ Icon(painterResource(id = R.drawable.visibility), null) } }, label = { Text("密码") }, visualTransformation = if(passwordHidden) PasswordVisualTransformation() else VisualTransformation.None)
BasicTextField
@Composablefun BasicTextField( value: String, onValueChange: (String) -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, readOnly: Boolean = false, textStyle: TextStyle = TextStyle.Default, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, keyboardActions: KeyboardActions = KeyboardActions.Default, singleLine: Boolean = false, maxLines: Int = Int.MAX_VALUE, visualTransformation: VisualTransformation = VisualTransformation.None, onTextLayout: (TextLayoutResult) -> Unit = {}, // 当输入框内文本触发更新时候的回调,包括了当前文本的各种信息 interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, cursorBrush: Brush = SolidColor(Color.Black), // 输入框光标的颜色 decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit = @Composable { innerTextField -> innerTextField() } // 是一个允许在 TextField 周围添加修饰的 @Composable lambda // 我们需要在布局中调用 innerTextField() 才能完成 TextField 的构建)
使用 BasicTextField 可以让你拥有更高的自定义效果
1. 简单使用
一个简单的使用例子如下:
var text by remember { mutableStateOf("") }
Box( modifier = Modifier .fillMaxSize() .background(Color(0xFFD3D3D3)), contentAlignment = Alignment.Center) { BasicTextField( value = text, onValueChange = { text = it }, modifier = Modifier .background(Color.White, CircleShape) .height(35.dp) .fillMaxWidth(), decorationBox = { innerTextField -> Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(horizontal = 10.dp) ) { IconButton( onClick = { } ) { Icon(painterResource(id = R.drawable.mood), null) } Box( modifier = Modifier.weight(1f), contentAlignment = Alignment.CenterStart ) { innerTextField() } IconButton( onClick = { }, ) { Icon(Icons.Filled.Send, null) } } } )}
在刚才的例子中,我们在 decorationBox 里面写了很多布局组件,最后通过调用一次 innerTextFiled() 来完成输入框的构建。
2. 其他效果
代码查看:
var text by remember { mutableStateOf("") }
Box( modifier = Modifier .fillMaxSize() .background(Color(0xFFD3D3D3)), contentAlignment = Alignment.Center) { BasicTextField( value = text, onValueChange = { text = it }, modifier = Modifier .background(Color.White) .fillMaxWidth(), decorationBox = { innerTextField -> Column( modifier = Modifier.padding(vertical = 10.dp) ) { Row( verticalAlignment = Alignment.CenterVertically, ) { IconButton(onClick = {}) { Icon(painterResource(id = R.drawable.mood), contentDescription = null) } IconButton(onClick = {}) { Icon(painterResource(id = R.drawable.gif), contentDescription = null) } IconButton(onClick = {}) { Icon(painterResource(id = R.drawable.shortcut), contentDescription = null) } IconButton(onClick = {}) { Icon(painterResource(id = R.drawable.more), contentDescription = null) } } Box( modifier = Modifier.padding(horizontal = 10.dp) ) { innerTextField() } Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.End ) { TextButton(onClick = { /*TODO*/ }) { Text("发送") } Spacer(Modifier.padding(horizontal = 10.dp)) TextButton(onClick = { /*TODO*/ }) { Text("关闭") } } } } )}
更多
[BasicTextField 参数详情](
版权声明: 本文为 InfoQ 作者【坚果】的原创文章。
原文链接:【http://xie.infoq.cn/article/2223e68aa2740de89c62046d8】。文章转载请联系作者。
坚果
此间若无火炬,我便是唯一的光 2020.10.25 加入
公众号:“大前端之旅”,华为云享专家,InfoQ签约作者,51CTO博客首席体验官,专注于大前端技术的分享,包括Flutter,小程序,安卓,VUE,JavaScript。










评论