I would like to remove the purple line/indicator (see the following image) of TextField.
Is that possible or should I create my own custom TextField to achieve that?
This has been changed in the recent Jetpack Compose UI Beta release 1.0.0-beta01 now you can pass the
TextFieldDefaults with desired colors.
colors = TextFieldDefaults.textFieldColors(
focusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
backgroundColor = Color.LightGray,
)
example
TextField(
value = searchText,
onValueChange = { Log.d(HOME_COMPONENT, it) },
label = { Text(text = "Search") },
shape = RoundedCornerShape(10.dp),
leadingIcon = {
Image(
painter = painterResource(id = R.drawable.ic_search),
contentDescription = "search"
)
},
colors = TextFieldDefaults.textFieldColors(
focusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
backgroundColor = Color.LightGray,
)
)
image:
or if you want to customize the component according to your UI/UX then use the BasicTextField
#Composable
fun ToolbarComponent() {
var searchText by remember { mutableStateOf("") }
Row(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically
) {
Icon(
painter = painterResource(id = R.drawable.ic_search),
contentDescription = "search",
modifier = Modifier.size(20.dp),
tint = iconTintColor
)
Spacer(modifier = Modifier.size(16.dp))
BasicTextField(
value = searchText,
onValueChange = { searchText = it },
modifier = Modifier
.background(shape = RoundedCornerShape(10.dp), color = Color.LightGray)
.fillMaxWidth()
.padding(16.dp),
decorationBox = {
Text(text = "Search")
}
)
}
}
Starting with 1.2.0-alpha04 you can use the TextFieldDecorationBox together with BasicTextField to build a custom text field based on Material Design text fields.
In your case you can apply the indicatorLine modifier to define the focusedIndicatorLineThickness and the unfocusedIndicatorLineThickness parameters:
var text by remember { mutableStateOf("") }
val singleLine = true
val enabled = true
val interactionSource = remember { MutableInteractionSource() }
BasicTextField(
value = text,
onValueChange = { text = it },
modifier = Modifier
.indicatorLine(enabled, false,
interactionSource,
TextFieldDefaults.textFieldColors(),
focusedIndicatorLineThickness = 0.dp,
unfocusedIndicatorLineThickness = 0.dp
)
.background(
TextFieldDefaults.textFieldColors().backgroundColor(enabled).value,
TextFieldDefaults.TextFieldShape
)
.width(TextFieldDefaults.MinWidth),
singleLine = singleLine,
interactionSource = interactionSource
) { innerTextField ->
TextFieldDecorationBox(
value = text,
innerTextField = innerTextField,
enabled = enabled,
singleLine = singleLine,
visualTransformation = VisualTransformation.None,
interactionSource = interactionSource,
label = { Text("Label") }
)
}
Otherwise you can use TextField defining these attributes:
focusedIndicatorColor
unfocusedIndicatorColor
disabledIndicatorColor
Something like:
TextField(
....
colors = TextFieldDefaults.textFieldColors(
backgroundColor = .....,
focusedIndicatorColor = Transparent,
unfocusedIndicatorColor = Transparent)
)
If You use TextField in that you can give the activeColor to Color.Transparent
Note: activeColor is not only for indicator, its for label bottom indicator and cursor
Ex:
var text: String by mutableStateOf("")
TextField(value = text, onValueChange = {
text = it
}, activeColor = Color.Transparent)
As per the document, activeColor is
activeColor the color of the label, bottom indicator and the cursor
when the text field is in focus
If you want to use your own you can try BaseTextField
Actually (version alpha 7) this is the easiest version I have found to remove Divider.
Set activeColor and inactiveColor to Color.Transparent in order to hide the indicator line under the TextField, whatever his state.
If you add only inactiveColor to Color.Transparent, the line will be invisible only when TextField is not focused
Add textStyle = TextStyle(color = Color.White) in order to display the color, whenever if the TextField is focused or not.
This solution will remove the line, but also the cursor indicator. It's not the best for the moment but it's also the alpha actually on Compose.
TextField(
value = MyValue,
onValueChange = { },
textStyle = TextStyle(color = Color.White),
activeColor = Color.Transparent,
inactiveColor = Color.Transparent,
shape = RoundedCornerShape(20)
)
Related
I am trying to give a border color for textfield in jetpack compose but I couldn't find information about textfield border color or layout color I just found about How to change layout or border color of outlinedtextfield. Is there a solution like in outlinetextfield? at the textfield?
I want to do like this but for textfield
How to change the outline color of OutlinedTextField from jetpack compose?
hear is my textfield code:
TextField(
value = currentWeight,
modifier = Modifier
.fillMaxWidth()
.padding(5.dp),
onValueChange = { currentWeight = it },
label = { Text(text = "Mevcut kilon (kg)") },
shape = RoundedCornerShape(5.dp),
colors = TextFieldDefaults.textFieldColors(
textColor = Grey2,
disabledTextColor = Color.Transparent,
backgroundColor = Grey3,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
)
)
result:
I added focused label color in textfield colors part but it didn't work
EDIT
I did it like this #Gabriele Mariotti but there are some problems
val interactionSource = remember { MutableInteractionSource() }
val isFocused = interactionSource.collectIsFocusedAsState()
val shape = RoundedCornerShape(2.dp)
val borderModifier = if (isFocused.value) Modifier.border(1.dp,Red, shape) else Modifier
val singleLine = true
val enabled = true
BasicTextField(
value = currentWeight,
onValueChange = { currentWeight = it },
interactionSource = interactionSource,
enabled = enabled,
singleLine = singleLine,
modifier = borderModifier.background(
color = TextFieldDefaults.textFieldColors().backgroundColor(true).value,
shape = shape
)
) {
TextFieldDefaults.TextFieldDecorationBox(
value = currentWeight,
innerTextField = it,
singleLine = singleLine,
enabled = enabled,
label = { Text("Label") },
placeholder = { Text("Placeholder") },
visualTransformation = VisualTransformation.None,
interactionSource = interactionSource,
colors = TextFieldDefaults.textFieldColors()
)
}
ISSUES
TextFieldDefaults.TextFieldDecorationBox
And `Text()`
TextFieldDecorationBox is red color and error is Unresolved reference: TextFieldDecorationBox
label = { Text("Label") },
placeholder = { Text("Placeholder") },
Texts error
#Composable invocations can only happen from the context of a #Composable function
You can use BasicTextField applying a border modifier and TextFieldDecorationBox.
Something like:
val isFocused = interactionSource.collectIsFocusedAsState()
val shape = RoundedCornerShape(2.dp)
val borderModifier = if (isFocused.value) Modifier.border(1.dp,Red, shape) else Modifier
BasicTextField(
value = value,
onValueChange = { value = it },
interactionSource = interactionSource,
enabled = enabled,
singleLine = singleLine,
modifier = borderModifier.background(
color = TextFieldDefaults.textFieldColors().backgroundColor(enabled).value,
shape = shape
)
) {
TextFieldDefaults.TextFieldDecorationBox(
value = value,
innerTextField = it,
singleLine = singleLine,
enabled = enabled,
label = { Text("Label") },
placeholder = { Text("Placeholder") },
visualTransformation = VisualTransformation.None,
interactionSource = interactionSource,
colors = TextFieldDefaults.textFieldColors()
)
}
Quick question here:
Is this a bug inside jetpack compose TextField or am I missing something:
#Composable
fun TextFieldWithPlaceholder() {
val text = rememberSaveable {
mutableStateOf("")
}
Box(modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colors.background)) {
TextField(
modifier = Modifier
.background(Color.Blue)
.size(width = 300.dp, height = 50.dp),
value = text.value,
onValueChange = { value ->
text.value = value
},
singleLine = true,
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
focusedLabelColor = Color.Transparent,
unfocusedLabelColor = Color.Transparent,
placeholderColor = Color.Red,
cursorColor = Color.White
),
placeholder = {
Text(
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
text = "Placeholder"
)
},
textStyle = MaterialTheme.typography.body2.copy(textAlign = TextAlign.Center)
)
}
}
If you build the project with this composable, and tap inside the input field, you'll notice that the cursor is behind the placeholder text (talking about the Z axis). Parts of the cursor are not visible due to "Placeholder" text being on top of it.
Is there a way to force it to be on top of placeholder?
Thanks in advance
I almost completely successfully implemented the custom search component I needed, but I have one last problem. I need my component to be only 45dp to match the designer's requirements, but at that height, due to the TextField padding, it's clipping the text on top. I leave you below a screenshot of what is happening and the code I have. Is there any way to resolve this?
I'm new to Jetpack Compose and that's all I need to close this component.
#Preview
#Composable
fun SearchTextField() {
val state = remember { mutableStateOf(TextFieldValue("")) }
TextField(
value = state.value,
onValueChange = { value -> state.value = value },
textStyle = TextStyle18Normal,
placeholder = {
Text(text = stringResource(id = R.string.search), style = TextStyle18Normal)
},
trailingIcon = {
Image(
painter = painterResource(id = R.drawable.ic_search),
contentDescription = ""
)
},
singleLine = true,
shape = RoundedCornerShape(Dimen13),
colors = TextFieldDefaults.textFieldColors(
cursorColor = Color.DarkGray,
trailingIconColor = colorResource(id = R.color.purple),
backgroundColor = Color.White,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent
),
modifier = Modifier
.width(Dimen320)
.height(Dimen45)
)
}
If I remove the .height(45) my problem is solved, but the component is not correct.
The TextField has hardcoded paddings.
Starting with 1.2.0 you can use the BasicTextField together with the TextFieldDecorationBox. With the contentPadding attribute you can define custom vertical paddings.
Something like:
val colors = TextFieldDefaults.textFieldColors(backgroundColor = White)
BasicTextField(
value = value,
onValueChange = onValueChange,
textStyle = TextStyle.Default.copy(fontSize = 18.sp),
modifier = modifier
.background(
color = colors.backgroundColor(enabled).value,
shape = RoundedCornerShape(13.dp). //rounded corners
)
.indicatorLine(
enabled = enabled,
isError = false,
interactionSource = interactionSource,
colors = colors,
focusedIndicatorLineThickness = 0.dp, //to hide the indicator line
unfocusedIndicatorLineThickness = 0.dp //to hide the indicator line
)
.height(45.dp),
interactionSource = interactionSource,
enabled = enabled,
singleLine = singleLine
) {
TextFieldDefaults.TextFieldDecorationBox(
value = value,
innerTextField = it,
singleLine = singleLine,
enabled = enabled,
visualTransformation = VisualTransformation.None,
trailingIcon = { /* ... */ },
placeholder = { /* ... */ },
interactionSource = interactionSource,
// keep horizontal paddings but change the vertical
contentPadding = TextFieldDefaults.textFieldWithoutLabelPadding(
top = 0.dp, bottom = 0.dp
)
)
}
I'm trying to create a TextField, in Jetpack compose with an underbar but without any other border or background. How do I do this?
This is the code I'm currently using:
val query = remember {mutableStateOf("")}
TextField(
value = query.value,
onValueChange = { newValue -> query.value = newValue },
label={Text("Dummy", color = colorResource(id = R.color.fade_green))},
textStyle = TextStyle(
textAlign = TextAlign.Start,
color = colorResource(id = R.color.fade_green),
fontFamily = FontFamily(Font(R.font.poppins_regular)),
fontSize = 14.sp,
),
modifier = Modifier
.padding(start = 30.dp).border(0.dp, Color.Red),
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent
)
)
Starting with 1.2.0 you can use the BasicTextField + TextFieldDecorationBox.
Something like:
BasicTextField(
value = text,
onValueChange = {text = it},
interactionSource = interactionSource,
textStyle = mergedTextStyle,
enabled = enabled,
singleLine = true,
modifier = Modifier
.background(
color = White, //Background color
shape = TextFieldDefaults.TextFieldShape
)
.indicatorLine(
enabled = enabled,
isError = false,
interactionSource = interactionSource,
colors = colors,
focusedIndicatorLineThickness = 2.dp, //width of the indicator
unfocusedIndicatorLineThickness = 2.dp
)
) {
TextFieldDefaults.TextFieldDecorationBox(
value = text,
enabled = enabled,
singleLine = true,
innerTextField = it,
visualTransformation = VisualTransformation.None,
interactionSource = interactionSource,
label = { Text("Label") },
)
}
With the 1.0.0 you can just use the colors attribute to define a Color.Transparent background.
var text by remember { mutableStateOf("") }
TextField(
value = text,
onValueChange = {
text = it
},
label = { Text("label") },
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
//Color of indicator = underbar
focusedIndicatorColor = ....,
unfocusedIndicatorColor = ....,
disabledIndicatorColor = ....
)
)
If you want to change the indicatorWidth currently there isn't a built-in parameter.
You can use the .drawBehind modifier to draw a line. Something like:
val interactionSource = remember { MutableInteractionSource() }
val isFocused by interactionSource.collectIsFocusedAsState()
val indicatorColor = if (isFocused) Color.Red else Color.Gray
val indicatorWidth = 4.dp
TextField(
value = text,
onValueChange = {
text = it },
label={Text("Label")},
interactionSource = interactionSource,
modifier = Modifier
.drawBehind {
val strokeWidth = indicatorWidth.value * density
val y = size.height - strokeWidth / 2
drawLine(
indicatorColor,
Offset(0f, y),
Offset(size.width, y),
strokeWidth
)
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
focusedIndicatorColor = Transparent,
unfocusedIndicatorColor = Transparent,
disabledIndicatorColor = Transparent
)
)
In general, most components in Jetpack Compose seem to be very easy to customize.
However, the same cannot be said for the TextField. For example, say that I wanted to make something like this:
One would think that simply wrapping the BaseTextField would work. However, it appears that there has been a bug in the BaseTextField component, and I have opened an issue. This bug will not permit the user to focus the text field after focusing-away from it once already, until the component is re-rendered.
Citing this, I attempted to customize the OutlinedTextField and TextField components, but am not able to customize them to look like the image above. Were it not for the fact that the cursor color uses the activeColor property, I could make it work.
What would be a proper work-around to create a usable text field that looks like the above?
You can use the TextField:
removing the label with label = null
applying custom color with the TextFieldDefaults.textFieldColors parameter to hide the indicator.
adding in the onValueChange a function to fix the max number of characters as described here
Finally use a Column to add 2 Text composables to complete the external label and counter text.
Something like:
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()
)
By this exemple you can learn a lot. With 1.0.0 you can do like this:
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
)
}
Well, until the issue I mentioned is resolved, the choices are:
Roll back to Compose version 1.0.0-alpha04 (issue was introduced in alpha05)
Add a border to a TextField or OutlinedTextField as so:
TextField(
value = myValue,
onValueChange = myOnChange,
modifier = Modifier.clip(myShape).border(5.dp, myColor)
)
In addition to Gabriele Mariotti's Answer
If you like to have custom color for your cursor, you can achieve it using:
Column(){
//External label
Text(
...
...
)
TextField(
...
...
colors = TextFieldDefaults.textFieldColors(
backgroundColor = ...,
focusedIndicatorColor = ...,
unfocusedIndicatorColor = ...,
cursorColor = Color.Black)
)
//counter message
Text(
...
...
)