Dense TextField in Jetpack Compose - android

In the old View system, we can make TextInputLayout dense using style Widget.MaterialComponents.TextInputLayout.FilledBox.Dense.
How can I create a dense variant of TextField in Compose?

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.
To create a dense text field, use contentPadding parameter to decrease the paddings around the input field.
Something like:
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())
.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") },
contentPadding = TextFieldDefaults.textFieldWithLabelPadding(
start = 4.dp,
end = 4.dp,
bottom = 4.dp // make it dense
)
)
}

Related

How to change border color of textfield in jetpack compose?

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

Jetpack Compose - How to use custom height on TextFieldDefaults.OutlinedTextFieldDecorationBox [duplicate]

This question already has answers here:
Jetpack Compose Decrease height of TextField
(5 answers)
Closed 4 months ago.
I'm trying to create a custom TextField using Android Jetpack compose, see below
TextFieldDefaults.OutlinedTextFieldDecorationBox(
contentPadding = PaddingValues(vertical = 10.dp),
value = searchText,
innerTextField = innerTextField,
enabled = enabled,
singleLine = singleLine,
visualTransformation = VisualTransformation.None,
interactionSource = interactionSource,
colors = textFieldColors,
leadingIcon = {
Icon(
modifier = Modifier.size(leadingIconSize),
painter = painterResource(id = R.drawable.ic_search),
contentDescription = ""
)
},
placeholder = {
Text("what is doin ")
}
)
The height of the text field should be 36dp due to design requirements, however the text field has its own height about 56dp.
I could not find any information how to customize that value so I used the parameter contentPadding to achieve the goal.
However, it seems too ugly for me. Is there any other way to achieve to implement this?
Thanks in advance.
Apply the height modifier to the BasicTextField.
Something like:
BasicTextField(
value = text,
onValueChange = { text = it },
modifier = Modifier
.height(36.dp),
singleLine = singleLine,
interactionSource = interactionSource
) { innerTextField ->
TextFieldDefaults.OutlinedTextFieldDecorationBox(
value = text,
innerTextField = innerTextField,
enabled = enabled,
singleLine = singleLine,
visualTransformation = VisualTransformation.None,
interactionSource = interactionSource,
contentPadding = TextFieldDefaults.textFieldWithoutLabelPadding(
top = 0.dp,
bottom = 0.dp
)
)
}

How do I change the internal margins in the OutlinedTextField? [duplicate]

I want to customize TextField composable in Jetpack Compose. I am trying to achieve the result in the image below, but somehow TextField has some default paddings which i couldn't find how to change values of. I want to remove default paddings and customize it
(The image on the right one is the result i achieved. I drew a border so that you can see it has padding, btw below that TextField are just Text composables, they aren't TextFields)
Below is my TextField code
TextField(
value = "",
onValueChange = {},
modifier = Modifier
.weight(1F)
.padding(0.dp)
.border(width = 1.dp, color = Color.Red),
placeholder = {
Text(
"5555 5555 5555 5555", style = TextStyle(
color = Color.Gray
)
)
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent
),
)
You can use BasicTextField, it's a plain text field without any decorations. Note that it doesn't have placeholder/hint too, you have to implement those by yourself if you need.
BasicTextField(value = "", onValueChange = {}, Modifier.fillMaxWidth())
Since 1.2.0-alpha04 it's much easier to make your BasicTextField look like TextField or OutlinedTextField. You can copy source code of TextField, which is pretty short since most of logic was moved into TextFieldDefaults.TextFieldDecorationBox, and pass the needed padding value into contentPadding parameter of TextFieldDefaults.TextFieldDecorationBox.
In the latest alpha release (androidx.compose.material:material:1.2.0-alpha04) they exposed TextFieldDefaults.TextFieldDecorationBox.
This is the implementation of the decorationBox composable used in the material TextField implementation.
You can use it as follows:
val interactionSource = remember { MutableInteractionSource() }
BasicTextField(
value = value,
onValueChange = onValueChange,
modifier = modifier,
visualTransformation = visualTransformation,
interactionSource = interactionSource,
enabled = enabled,
singleLine = singleLine,
) { innerTextField ->
TextFieldDefaults.TextFieldDecorationBox(
value = value,
visualTransformation = visualTransformation,
innerTextField = innerTextField,
singleLine = singleLine,
enabled = enabled,
interactionSource = interactionSource,
contentPadding = PaddingValues(0.dp), // this is how you can remove the padding
)
}
This will allow you to remove the padding but still get the rest of the features that come with TextField.
Remember to use the same MutableInteractionSource for both the BasicTextField and the TextFieldDefaults.TextFieldDecorationBox.
The official documentation I linked to above shows more examples if its usage.
Thank you all, i did use BasicTextField and achieved the result i wanted :)
#Composable
fun BottomOutlineTextField(placeholder: String, value: String, onValueChange: (String) -> Unit) {
BasicTextField(
modifier = Modifier.fillMaxWidth(),
value = value,
onValueChange = onValueChange,
textStyle = TextStyle(
color = if (isSystemInDarkTheme()) Color(0xFF969EBD) else Color.Gray
),
decorationBox = { innerTextField ->
Row(modifier = Modifier.fillMaxWidth()) {
if (value.isEmpty()) {
Text(
text = placeholder,
color = if (isSystemInDarkTheme()) Color(0xFF969EBD) else Color.Gray,
fontSize = 14.sp
)
}
}
innerTextField()
}
)
}
I wanted to cut off the 16.dp at the start. I managed to this in the following way:
BoxWithConstraints(modifier = Modifier
.clipToBounds()
) {
TextField(modifier = Modifier
.requiredWidth(maxWidth+16.dp)
.offset(x=(-8).dp))
}
I solved this problem by coping all source code from TextField and replace this lines of code :
val paddingToIcon = TextFieldPadding - HorizontalIconPadding
// val padding = Modifier.padding(
// start = if (leading != null) paddingToIcon else TextFieldPadding,
// end = if (trailing != null) paddingToIcon else TextFieldPadding
// )
val padding = Modifier.padding(
start = if (leading != null) paddingToIcon else 0.dp,
end = if (trailing != null) paddingToIcon else 0.dp
)
And this work great!
You can put your TextField in a Box and apply modifiers, e.g.
Box(
modifier = Modifier.background(
shape = RoundedCornerShape(percent = 10),
color = colorBackgroundGray
)
) {
TextField(
value = text,
onValueChange = onValueChange,
modifier = Modifier.fillMaxWidth().padding(8.dp, 0.dp, 0.dp, 0.dp)...
}
Using
...
decorationBox{
TextFieldDefaults.TextFieldDecorationBox(
....
)
required me to add the anotation #OptIn(ExperimentalMaterialApi::class) which seems to not be a good aproach for a release scenario.
Instead, I could get the result I as expecteing by the following implementation:
#Composable
fun Input(
text: TextFieldValue = TextFieldValue(),
onValueChanged: (TextFieldValue) -> Unit = { },
keyboardType: KeyboardType = KeyboardType.Text,
imeAction: ImeAction = ImeAction.Done,
isEnable: Boolean = true,
singleLine: Boolean = true,
shape: Shape = rounded,
autoCorrect: Boolean = false,
innerPadding: PaddingValues = PaddingValues(15.dp, 7.dp)
) {
val focusManager = LocalFocusManager.current
val fontSize = 16.sp
BasicTextField(
value = text,
onValueChange = onValueChanged,
Modifier
.clip(shape)
.border(1.dp, Color.Gray, shape)
.background(Color.White),
textStyle = TextStyle(color = Color.Black, fontSize = fontSize),
enabled = isEnable,
singleLine = singleLine,
keyboardOptions = KeyboardOptions(
KeyboardCapitalization.None,
autoCorrect,
keyboardType,
imeAction
),
keyboardActions = KeyboardActions(
onAny = {
focusManager.clearFocus()
}
),
decorationBox = {
Box(
modifier = Modifier.padding(innerPadding)
) {
if(text.text.isBlank()) {
Text(
text = "Search",
style = TextStyle(color = Color.Black, fontSize = fontSize)
)
}
it()
}
}
)
}
Hope it helps somebody.
It is so easy, just copy all TextField or OutlinedTextField functions and remove defaultMinSize then add contentPadding
After that, you can use it instead of main TextField or OutlinedTextField
for OutlinedTextField:
#Composable
fun BorderTextField(
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.Default,
singleLine: Boolean = false,
maxLines: Int = Int.MAX_VALUE,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = MaterialTheme.shapes.small,
colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
) {
// If color is not provided via the text style, use content color as a default
val textColor = textStyle.color.takeOrElse {
colors.textColor(enabled).value
}
val mergedTextStyle = textStyle.merge(TextStyle(color = textColor))
#OptIn(ExperimentalMaterialApi::class)
BasicTextField(
value = value,
modifier = if (label != null) {
modifier
// Merge semantics at the beginning of the modifier chain to ensure padding is
// considered part of the text field.
.semantics(mergeDescendants = true) {}
} else {
modifier
}
.background(colors.backgroundColor(enabled).value, shape),
onValueChange = onValueChange,
enabled = enabled,
readOnly = readOnly,
textStyle = mergedTextStyle,
cursorBrush = SolidColor(colors.cursorColor(isError).value),
visualTransformation = visualTransformation,
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
interactionSource = interactionSource,
singleLine = singleLine,
maxLines = maxLines,
decorationBox = #Composable { innerTextField ->
TextFieldDefaults.OutlinedTextFieldDecorationBox(
value = value,
visualTransformation = visualTransformation,
innerTextField = innerTextField,
placeholder = placeholder,
label = label,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
singleLine = singleLine,
enabled = enabled,
isError = isError,
interactionSource = interactionSource,
colors = colors,
contentPadding = TextFieldDefaults.outlinedTextFieldPadding(
start = 0.dp,
top = 0.dp,
end = 0.dp,
bottom = 0.dp
),
border = {
TextFieldDefaults.BorderBox(
enabled,
isError,
interactionSource,
colors,
shape
)
}
)
}
)
}
Actually that is innate, it follows material guidelines. If you wish to disable it, an alternative could be to set the height of the TextField explicitly, and matching it with the font size of the text. That way it will only extend till the text does. Another way would be to look at the source of TextField. You could just copy the source and make modifications to meet your requirements. The former sounds like an easy fix, however, the latter is no big deal as well. It is doable, and is a recommended practice to customize behavior for your needs. Also, just as a side note, I don't think it is a good idea to disable that padding. It was added to design guidelines since it seems pretty sensible and natural to have it. Sometimes we find some designs attractive when we think about them but they aren't as good when seen implemented.

remove default padding on jetpack compose textfield

I want to customize TextField composable in Jetpack Compose. I am trying to achieve the result in the image below, but somehow TextField has some default paddings which i couldn't find how to change values of. I want to remove default paddings and customize it
(The image on the right one is the result i achieved. I drew a border so that you can see it has padding, btw below that TextField are just Text composables, they aren't TextFields)
Below is my TextField code
TextField(
value = "",
onValueChange = {},
modifier = Modifier
.weight(1F)
.padding(0.dp)
.border(width = 1.dp, color = Color.Red),
placeholder = {
Text(
"5555 5555 5555 5555", style = TextStyle(
color = Color.Gray
)
)
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent
),
)
You can use BasicTextField, it's a plain text field without any decorations. Note that it doesn't have placeholder/hint too, you have to implement those by yourself if you need.
BasicTextField(value = "", onValueChange = {}, Modifier.fillMaxWidth())
Since 1.2.0-alpha04 it's much easier to make your BasicTextField look like TextField or OutlinedTextField. You can copy source code of TextField, which is pretty short since most of logic was moved into TextFieldDefaults.TextFieldDecorationBox, and pass the needed padding value into contentPadding parameter of TextFieldDefaults.TextFieldDecorationBox.
In the latest alpha release (androidx.compose.material:material:1.2.0-alpha04) they exposed TextFieldDefaults.TextFieldDecorationBox.
This is the implementation of the decorationBox composable used in the material TextField implementation.
You can use it as follows:
val interactionSource = remember { MutableInteractionSource() }
BasicTextField(
value = value,
onValueChange = onValueChange,
modifier = modifier,
visualTransformation = visualTransformation,
interactionSource = interactionSource,
enabled = enabled,
singleLine = singleLine,
) { innerTextField ->
TextFieldDefaults.TextFieldDecorationBox(
value = value,
visualTransformation = visualTransformation,
innerTextField = innerTextField,
singleLine = singleLine,
enabled = enabled,
interactionSource = interactionSource,
contentPadding = PaddingValues(0.dp), // this is how you can remove the padding
)
}
This will allow you to remove the padding but still get the rest of the features that come with TextField.
Remember to use the same MutableInteractionSource for both the BasicTextField and the TextFieldDefaults.TextFieldDecorationBox.
The official documentation I linked to above shows more examples if its usage.
Thank you all, i did use BasicTextField and achieved the result i wanted :)
#Composable
fun BottomOutlineTextField(placeholder: String, value: String, onValueChange: (String) -> Unit) {
BasicTextField(
modifier = Modifier.fillMaxWidth(),
value = value,
onValueChange = onValueChange,
textStyle = TextStyle(
color = if (isSystemInDarkTheme()) Color(0xFF969EBD) else Color.Gray
),
decorationBox = { innerTextField ->
Row(modifier = Modifier.fillMaxWidth()) {
if (value.isEmpty()) {
Text(
text = placeholder,
color = if (isSystemInDarkTheme()) Color(0xFF969EBD) else Color.Gray,
fontSize = 14.sp
)
}
}
innerTextField()
}
)
}
I wanted to cut off the 16.dp at the start. I managed to this in the following way:
BoxWithConstraints(modifier = Modifier
.clipToBounds()
) {
TextField(modifier = Modifier
.requiredWidth(maxWidth+16.dp)
.offset(x=(-8).dp))
}
I solved this problem by coping all source code from TextField and replace this lines of code :
val paddingToIcon = TextFieldPadding - HorizontalIconPadding
// val padding = Modifier.padding(
// start = if (leading != null) paddingToIcon else TextFieldPadding,
// end = if (trailing != null) paddingToIcon else TextFieldPadding
// )
val padding = Modifier.padding(
start = if (leading != null) paddingToIcon else 0.dp,
end = if (trailing != null) paddingToIcon else 0.dp
)
And this work great!
You can put your TextField in a Box and apply modifiers, e.g.
Box(
modifier = Modifier.background(
shape = RoundedCornerShape(percent = 10),
color = colorBackgroundGray
)
) {
TextField(
value = text,
onValueChange = onValueChange,
modifier = Modifier.fillMaxWidth().padding(8.dp, 0.dp, 0.dp, 0.dp)...
}
Using
...
decorationBox{
TextFieldDefaults.TextFieldDecorationBox(
....
)
required me to add the anotation #OptIn(ExperimentalMaterialApi::class) which seems to not be a good aproach for a release scenario.
Instead, I could get the result I as expecteing by the following implementation:
#Composable
fun Input(
text: TextFieldValue = TextFieldValue(),
onValueChanged: (TextFieldValue) -> Unit = { },
keyboardType: KeyboardType = KeyboardType.Text,
imeAction: ImeAction = ImeAction.Done,
isEnable: Boolean = true,
singleLine: Boolean = true,
shape: Shape = rounded,
autoCorrect: Boolean = false,
innerPadding: PaddingValues = PaddingValues(15.dp, 7.dp)
) {
val focusManager = LocalFocusManager.current
val fontSize = 16.sp
BasicTextField(
value = text,
onValueChange = onValueChanged,
Modifier
.clip(shape)
.border(1.dp, Color.Gray, shape)
.background(Color.White),
textStyle = TextStyle(color = Color.Black, fontSize = fontSize),
enabled = isEnable,
singleLine = singleLine,
keyboardOptions = KeyboardOptions(
KeyboardCapitalization.None,
autoCorrect,
keyboardType,
imeAction
),
keyboardActions = KeyboardActions(
onAny = {
focusManager.clearFocus()
}
),
decorationBox = {
Box(
modifier = Modifier.padding(innerPadding)
) {
if(text.text.isBlank()) {
Text(
text = "Search",
style = TextStyle(color = Color.Black, fontSize = fontSize)
)
}
it()
}
}
)
}
Hope it helps somebody.
It is so easy, just copy all TextField or OutlinedTextField functions and remove defaultMinSize then add contentPadding
After that, you can use it instead of main TextField or OutlinedTextField
for OutlinedTextField:
#Composable
fun BorderTextField(
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.Default,
singleLine: Boolean = false,
maxLines: Int = Int.MAX_VALUE,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = MaterialTheme.shapes.small,
colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
) {
// If color is not provided via the text style, use content color as a default
val textColor = textStyle.color.takeOrElse {
colors.textColor(enabled).value
}
val mergedTextStyle = textStyle.merge(TextStyle(color = textColor))
#OptIn(ExperimentalMaterialApi::class)
BasicTextField(
value = value,
modifier = if (label != null) {
modifier
// Merge semantics at the beginning of the modifier chain to ensure padding is
// considered part of the text field.
.semantics(mergeDescendants = true) {}
} else {
modifier
}
.background(colors.backgroundColor(enabled).value, shape),
onValueChange = onValueChange,
enabled = enabled,
readOnly = readOnly,
textStyle = mergedTextStyle,
cursorBrush = SolidColor(colors.cursorColor(isError).value),
visualTransformation = visualTransformation,
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
interactionSource = interactionSource,
singleLine = singleLine,
maxLines = maxLines,
decorationBox = #Composable { innerTextField ->
TextFieldDefaults.OutlinedTextFieldDecorationBox(
value = value,
visualTransformation = visualTransformation,
innerTextField = innerTextField,
placeholder = placeholder,
label = label,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
singleLine = singleLine,
enabled = enabled,
isError = isError,
interactionSource = interactionSource,
colors = colors,
contentPadding = TextFieldDefaults.outlinedTextFieldPadding(
start = 0.dp,
top = 0.dp,
end = 0.dp,
bottom = 0.dp
),
border = {
TextFieldDefaults.BorderBox(
enabled,
isError,
interactionSource,
colors,
shape
)
}
)
}
)
}
Actually that is innate, it follows material guidelines. If you wish to disable it, an alternative could be to set the height of the TextField explicitly, and matching it with the font size of the text. That way it will only extend till the text does. Another way would be to look at the source of TextField. You could just copy the source and make modifications to meet your requirements. The former sounds like an easy fix, however, the latter is no big deal as well. It is doable, and is a recommended practice to customize behavior for your needs. Also, just as a side note, I don't think it is a good idea to disable that padding. It was added to design guidelines since it seems pretty sensible and natural to have it. Sometimes we find some designs attractive when we think about them but they aren't as good when seen implemented.

Jetpack Compose how to remove EditText/TextField underline and keep cursor?

Hi I need to remove the underline in my TextField because it look ugly when the TextField is circular. I have sat the activeColor to transparent, but then the cursor wont show (because it's transparent). How can I remove the underline/activeColor and keep the cursor?
Here is my Circular TextField code:
#Composable
fun SearchBar(value: String) {
// we are creating a variable for
// getting a value of our text field.
val inputvalue = remember { mutableStateOf(TextFieldValue()) }
TextField(
// below line is used to get
// value of text field,
value = inputvalue.value,
// below line is used to get value in text field
// on value change in text field.
onValueChange = { inputvalue.value = it },
// below line is used to add placeholder
// for our text field.
placeholder = { Text(text = "Firmanavn") },
// modifier is use to add padding
// to our text field, and a circular border
modifier = Modifier.padding(all = 16.dp).fillMaxWidth().border(1.dp, Color.LightGray, CircleShape),
shape = CircleShape,
// keyboard options is used to modify
// the keyboard for text field.
keyboardOptions = KeyboardOptions(
// below line is use for capitalization
// inside our text field.
capitalization = KeyboardCapitalization.None,
// below line is to enable auto
// correct in our keyboard.
autoCorrect = true,
// below line is used to specify our
// type of keyboard such as text, number, phone.
keyboardType = KeyboardType.Text,
),
// below line is use to specify
// styling for our text field value.
textStyle = TextStyle(color = Color.Black,
// below line is used to add font
// size for our text field
fontSize = TextUnit.Companion.Sp(value = 15),
// below line is use to change font family.
fontFamily = FontFamily.SansSerif),
// below line is use to give
// max lines for our text field.
maxLines = 1,
// active color is use to change
// color when text field is focused.
activeColor = Color.Gray,
// single line boolean is use to avoid
// textfield entering in multiple lines.
singleLine = true,
// inactive color is use to change
// color when text field is not focused.
inactiveColor = Color.Transparent,
backgroundColor = colorResource(id = R.color.white_light),
// trailing icons is use to add
// icon to the end of tet field.
trailingIcon = {
Icon(Icons.Filled.Search, tint = colorResource(id = R.color.purple_700))
},
)
You can define these attributes to apply a Transparent color:
focusedIndicatorColor
unfocusedIndicatorColor
disabledIndicatorColor
Something like:
TextField(
//..
colors = TextFieldDefaults.textFieldColors(
textColor = Color.Gray,
disabledTextColor = Color.Transparent,
backgroundColor = Color.White,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent
)
)
Starting with 1.2.0 you can also use the new OutlinedTextFieldDecorationBox together with BasicTextField customizing the border or the indicator line.
val interactionSource = remember { MutableInteractionSource() }
val enabled = true
val singleLine = true
val colors = TextFieldDefaults.outlinedTextFieldColors()
BasicTextField(
value = value,
onValueChange = onValueChange,
modifier = modifier,
// internal implementation of the BasicTextField will dispatch focus events
interactionSource = interactionSource,
enabled = enabled,
singleLine = singleLine
) {
TextFieldDefaults.OutlinedTextFieldDecorationBox(
value = value,
visualTransformation = VisualTransformation.None,
innerTextField = it,
// same interaction source as the one passed to BasicTextField to read focus state
// for text field styling
interactionSource = interactionSource,
enabled = enabled,
singleLine = singleLine,
// update border thickness and shape
border = {
TextFieldDefaults.BorderBox(
enabled = enabled,
isError = false,
colors = colors,
interactionSource = interactionSource,
shape = CircleShape,
unfocusedBorderThickness = 1.dp,
focusedBorderThickness = 1.dp
)
}
)
}
Also you can use a TextFieldDecorationBox applying the indicatorLine modifier specifying the focusedIndicatorLineThickness and unfocusedIndicatorLineThickness values:
val colors = TextFieldDefaults.textFieldColors(
backgroundColor = White,
focusedIndicatorColor = Gray)
BasicTextField(
modifier = Modifier
.border(1.dp, Color.LightGray, CircleShape)
.indicatorLine(
enabled = enabled,
isError = false,
colors = colors,
interactionSource = interactionSource,
focusedIndicatorLineThickness = 0.dp,
unfocusedIndicatorLineThickness = 0.dp
)
.background(colors.backgroundColor(enabled).value, CircleShape),
) {
TextFieldDecorationBox(
//...
colors = colors
)
}
If you don't need TextField parameters / functions like collapsing label, placeholder, etc. you can use a layer of Text / BasicTextField to create a SearchField (which is a suggested workaround according to issue FilledTextField: can't remove bottom indicator ):
#Composable
fun Search(
hint: String,
endIcon: ImageVector? = Icons.Default.Cancel,
onValueChanged: (String) -> Unit,
) {
var textValue by remember { mutableStateOf(TextFieldValue()) }
Surface(
shape = RoundedCornerShape(50),
color = searchFieldColor
) {
Box(
modifier = Modifier
.preferredHeight(40.dp)
.padding(start = 16.dp, end = 12.dp),
contentAlignment = Alignment.CenterStart
)
{
if (textValue.text.isEmpty()) {
Text(
text = "Search...",
style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onSurface.copy(ContentAlpha.medium)),
)
}
Row(
verticalAlignment = Alignment.CenterVertically
) {
BasicTextField(
modifier = Modifier.weight(1f),
value = textValue,
onValueChange = { textValue = it; onValueChanged(textValue.text) },
singleLine = true,
cursorColor = YourColor,
)
endIcon?.let {
AnimatedVisibility(
visible = textValue.text.isNotEmpty(),
enter = fadeIn(),
exit = fadeOut()
) {
Image(
modifier = Modifier
.preferredSize(24.dp)
.clickable(
onClick = { textValue = TextFieldValue() },
indication = null
),
imageVector = endIcon,
colorFilter = iconColor
)
}
}
}
}
}
}

Categories

Resources