Align Textfield label to start of underbar using Jetpack Compose - android

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
)
)

Related

Jetpack Compose TextField - Cursor behind placeholder

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

How to change TextField's indicator width in Jetpack Compose?

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
)
)

How change OutlineTextField border width in Android Jetpack Compose?

My code:
OutlinedTextField(
value = state.value,
onValueChange = { state.value = it },
modifier = Modifier.fillMaxWidth().padding(start = 30.dp, end = 30.dp),
label = { Text(text = "Something", fontSize = 14.sp) },
shape = RoundedCornerShape(12.dp),
)
I want to increase the border width so that the colors focusedBorderColor, disabledBorderColor are supported.
Outline border is defined as a constant value in OutlinedTextField.
private val IndicatorUnfocusedWidth = 1.dp
private val IndicatorFocusedWidth = 2.dp
There is no direct way to override these values.
So, you have to create complete custom TextField Composables if you need to achieve dynamic border width.
You can copy-paste the complete code in OutlinedTextField.kt and TextFieldImpl.kt and modify them as required to create the custom Composables.
You can change OutlinedTextField border like this
var hasFocus by remember { mutableStateOf(false) }
OutlinedTextField(
modifier = modifier
.border(
width = 1.dp,
color = if (hasFocus) Color.Red else Color.Unspecified
)
.onFocusChanged { focusState -> hasFocus = focusState.hasFocus },
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = Color.Unspecified,
unfocusedBorderColor = Color.Unspecified
)
)
Another solution is to use BaseTextField instead of OutlinedTextField

Customise Focussed Indicator Line Android Compose TextField

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 )

How to create a TextField with underbar, without any background or border?

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
)
)

Categories

Resources