Is there a way to customise, (I would like to shorten the length) of the focussed indicator line on a TextField in Android Compose UI?
I know it's possible to hide it by setting the focusedIndicatorColor to Transparent as per example below:
TextField(
value = ...,
onValueChange = { ... },
label = { Text("...") },
modifier = Modifier.weight(1f).padding(horizontal = 8.dp, vertical = 6.dp),
shape = RoundedCornerShape(8.dp),
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.LightGray,
cursorColor = Color.Black,
disabledLabelColor = Color.LightGray,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent
)
)
The TextField follows the Material guidelines and there isn't a built-in parameter to change this behaviour.
You can use a workaround using the drawWithContent modifier:
val interactionSource = remember { MutableInteractionSource() }
val isFocused by interactionSource.collectIsFocusedAsState()
val TextFieldPadding = 6.dp //use this value to change the length of th e indicator
val indicatorColor = Color.Red
val indicatorWidth = 1.dp
TextField(
value = text,
onValueChange = {
text = it },
label={Text("Label")},
interactionSource = interactionSource,
modifier = Modifier
.drawWithContent {
drawContent()
if (isFocused) {
val strokeWidth = indicatorWidth.value * density
val y = size.height - strokeWidth / 2
drawLine(
indicatorColor,
Offset((TextFieldPadding).toPx(), y),
Offset(size.width - TextFieldPadding.toPx(), y),
strokeWidth
)
}
},
shape = RoundedCornerShape(8.dp),
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.LightGray,
cursorColor = Color.Black,
focusedIndicatorColor = Transparent,
unfocusedIndicatorColor = Transparent,
disabledIndicatorColor = Transparent
)
)
unfocused:
.
Focused:
You could try Modifier.indication() perhaps. I'm not really sure if it would work.
Modifier.indication( interactionSource = MutableInteractionSource(), indication = yourCustomIndicator )
Related
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've been wondering if there is a way to change TextField's indicator (underline) width.
There isn't a parameter to achieve it since TextField follows the Material guidelines.
You can use a custom modifier to draw a line at the bottom of the TextField:
fun Modifier.drawCustomIndicatorLine(
indicatorBorder: BorderStroke,
indicatorPadding : Dp = 0.dp
): Modifier {
val strokeWidthDp = indicatorBorder.width
return drawWithContent {
drawContent()
if (strokeWidthDp == Dp.Hairline) return#drawWithContent
val strokeWidth = strokeWidthDp.value * density
val y = size.height - strokeWidth / 2
drawLine(
indicatorBorder.brush,
Offset((indicatorPadding).toPx(), y),
Offset(size.width - indicatorPadding.toPx(), y),
strokeWidth
)
}
}
Then use it and apply a Transparent color to hide the default Indicator.
Something like:
val interactionSource = remember { MutableInteractionSource() }
val isFocused by interactionSource.collectIsFocusedAsState()
val indicatorColor = if (isFocused) Color.Red else Teal200
TextField(
value = text,
onValueChange = { text = it },
interactionSource = interactionSource,
modifier = Modifier.drawCustomIndicatorLine(
indicatorBorder = BorderStroke(1.dp,indicatorColor),
indicatorPadding = 10.dp
),
shape = RoundedCornerShape(8.dp),
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.LightGray,
cursorColor = Color.Black,
focusedIndicatorColor = Transparent,
unfocusedIndicatorColor = Transparent,
disabledIndicatorColor = Transparent
)
)
By default the label of Textfield is not aligned with the start position of underbar. There seems to be some empty space before the label text.
This is how my Textfields look like:
I want the label of my textfield to be aligned to the start position of underbar. How do I achieve this?
With 1.0.0 (tested with 1.0.0-beta07) the TextField follows the Material guidelines and there isn't a built-in parameter to change this behaviour.
You should use a BasicTextField with some specific styling.
Otherwise you can use the drawBehind modifier:
val interactionSource = remember { MutableInteractionSource() }
val isFocused by interactionSource.collectIsFocusedAsState()
val IndicatorUnfocusedWidth = 1.dp
val IndicatorFocusedWidth = 2.dp
val TextFieldPadding = 16.dp
val indicatorColor = if (isFocused) Color.Red else Color.Gray
val indicatorWidth = if (isFocused) IndicatorFocusedWidth else IndicatorUnfocusedWidth
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(TextFieldPadding.toPx(), y),
Offset(size.width - TextFieldPadding.toPx(), y),
strokeWidth
)
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
focusedIndicatorColor = Transparent,
unfocusedIndicatorColor = Transparent,
disabledIndicatorColor = Transparent
)
)
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
)
)
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)
)