Jetpack Compose:自定义 TextField 设计
Jetpack Compose: Custom TextField design
总的来说,Jetpack Compose 中的大多数组件似乎都非常容易定制。
但是,TextField
就不同了。例如,假设我想做这样的事情:
人们会认为简单地包装 BaseTextField
就可以了。但是,似乎 BaseTextField
组件中出现了错误,而我有 opened an issue。此错误将不允许用户在焦点离开文本字段后再次聚焦文本字段,直到组件重新呈现。
据此,我尝试自定义 OutlinedTextField
和 TextField
组件,但无法将它们自定义为如上图所示。要不是光标颜色用了activeColor
属性,我也能搞定
创建类似于上面的可用文本字段的正确解决方法是什么?
嗯,在 issue I mentioned 解决之前,选择是:
- 回滚到 Compose 版本
1.0.0-alpha04
(问题已在 alpha05
中引入)
- 为
TextField
或 OutlinedTextField
添加边框,如下所示:
TextField(
value = myValue,
onValueChange = myOnChange,
modifier = Modifier.clip(myShape).border(5.dp, myColor)
)
您可以使用 TextField
:
- 删除带有
label = null
的标签
- 使用
TextFieldDefaults.textFieldColors
参数应用自定义颜色以隐藏指示器。
- 在
onValueChange
中添加一个函数来修复所描述的最大字符数
最后使用 Column
添加 2 Text
可组合项来完成外部标签和计数器文本。
类似于:
var text by remember { mutableStateOf("") }
val maxChar = 5
Column(){
//External label
Text(
text = "Label",
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Start,
color = Blue
)
TextField(
value = text,
onValueChange = {
if (it.length <= maxChar) text = it
},
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 4.dp),
shape = RoundedCornerShape(8.dp),
trailingIcon = {
Icon(Icons.Filled.Add, "", tint = Blue)
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = ....,
focusedIndicatorColor = Color.Transparent, //hide the indicator
unfocusedIndicatorColor = .....)
)
//counter message
Text(
text = "${text.length} / $maxChar",
textAlign = TextAlign.End,
color = Blue,
style = MaterialTheme.typography.caption, //use the caption text style
modifier = Modifier.fillMaxWidth()
)
通过这个例子你可以学到很多东西。对于 1.0.0,您可以这样做:
Column {
var textState by remember { mutableStateOf("") }
val maxLength = 110
val lightBlue = Color(0xffd8e6ff)
val blue = Color(0xff76a9ff)
Text(
text = "Caption",
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 4.dp),
textAlign = TextAlign.Start,
color = blue
)
TextField(
modifier = Modifier.fillMaxWidth(),
value = textState,
colors = TextFieldDefaults.textFieldColors(
backgroundColor = lightBlue,
cursorColor = Color.Black,
disabledLabelColor = lightBlue,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent
),
onValueChange = {
if (it.length <= maxLength) textState = it
},
shape = RoundedCornerShape(8.dp),
singleLine = true,
trailingIcon = {
if (textState.isNotEmpty()) {
IconButton(onClick = { textState = "" }) {
Icon(
imageVector = Icons.Outlined.Close,
contentDescription = null
)
}
}
}
)
Text(
text = "${textState.length} / $maxLength",
modifier = Modifier
.fillMaxWidth()
.padding(top = 4.dp),
textAlign = TextAlign.End,
color = blue
)
}
除了
如果您想为光标设置自定义颜色,可以使用以下方法实现:
Column(){
//External label
Text(
...
...
)
TextField(
...
...
colors = TextFieldDefaults.textFieldColors(
backgroundColor = ...,
focusedIndicatorColor = ...,
unfocusedIndicatorColor = ...,
cursorColor = Color.Black)
)
//counter message
Text(
...
...
)
总的来说,Jetpack Compose 中的大多数组件似乎都非常容易定制。
但是,TextField
就不同了。例如,假设我想做这样的事情:
人们会认为简单地包装 BaseTextField
就可以了。但是,似乎 BaseTextField
组件中出现了错误,而我有 opened an issue。此错误将不允许用户在焦点离开文本字段后再次聚焦文本字段,直到组件重新呈现。
据此,我尝试自定义 OutlinedTextField
和 TextField
组件,但无法将它们自定义为如上图所示。要不是光标颜色用了activeColor
属性,我也能搞定
创建类似于上面的可用文本字段的正确解决方法是什么?
嗯,在 issue I mentioned 解决之前,选择是:
- 回滚到 Compose 版本
1.0.0-alpha04
(问题已在alpha05
中引入) - 为
TextField
或OutlinedTextField
添加边框,如下所示:TextField( value = myValue, onValueChange = myOnChange, modifier = Modifier.clip(myShape).border(5.dp, myColor) )
您可以使用 TextField
:
- 删除带有
label = null
的标签
- 使用
TextFieldDefaults.textFieldColors
参数应用自定义颜色以隐藏指示器。 - 在
onValueChange
中添加一个函数来修复所描述的最大字符数
最后使用 Column
添加 2 Text
可组合项来完成外部标签和计数器文本。
类似于:
var text by remember { mutableStateOf("") }
val maxChar = 5
Column(){
//External label
Text(
text = "Label",
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Start,
color = Blue
)
TextField(
value = text,
onValueChange = {
if (it.length <= maxChar) text = it
},
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 4.dp),
shape = RoundedCornerShape(8.dp),
trailingIcon = {
Icon(Icons.Filled.Add, "", tint = Blue)
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = ....,
focusedIndicatorColor = Color.Transparent, //hide the indicator
unfocusedIndicatorColor = .....)
)
//counter message
Text(
text = "${text.length} / $maxChar",
textAlign = TextAlign.End,
color = Blue,
style = MaterialTheme.typography.caption, //use the caption text style
modifier = Modifier.fillMaxWidth()
)
通过这个例子你可以学到很多东西。对于 1.0.0,您可以这样做:
Column {
var textState by remember { mutableStateOf("") }
val maxLength = 110
val lightBlue = Color(0xffd8e6ff)
val blue = Color(0xff76a9ff)
Text(
text = "Caption",
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 4.dp),
textAlign = TextAlign.Start,
color = blue
)
TextField(
modifier = Modifier.fillMaxWidth(),
value = textState,
colors = TextFieldDefaults.textFieldColors(
backgroundColor = lightBlue,
cursorColor = Color.Black,
disabledLabelColor = lightBlue,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent
),
onValueChange = {
if (it.length <= maxLength) textState = it
},
shape = RoundedCornerShape(8.dp),
singleLine = true,
trailingIcon = {
if (textState.isNotEmpty()) {
IconButton(onClick = { textState = "" }) {
Icon(
imageVector = Icons.Outlined.Close,
contentDescription = null
)
}
}
}
)
Text(
text = "${textState.length} / $maxLength",
modifier = Modifier
.fillMaxWidth()
.padding(top = 4.dp),
textAlign = TextAlign.End,
color = blue
)
}
除了
如果您想为光标设置自定义颜色,可以使用以下方法实现:
Column(){
//External label
Text(
...
...
)
TextField(
...
...
colors = TextFieldDefaults.textFieldColors(
backgroundColor = ...,
focusedIndicatorColor = ...,
unfocusedIndicatorColor = ...,
cursorColor = Color.Black)
)
//counter message
Text(
...
...
)