Say I have a Row and I want it to intercept click events, preventing BasicTextField from gaining focus. Is it possible?
Row(
modifier = Modifier.clickable {}
) {
BasicTextField(...)
}
Using Enabled value in Textfield you can prevent BasicTextField from gaining focus.
TextField(
value = text,
onValueChange = { text = it},
enabled = false,
modifier = Modifier
.clickable { text= "Clicked"},
colors = TextFieldDefaults.textFieldColors(
disabledTextColor = LocalContentColor.current.copy(LocalContentAlpha.current),
disabledLabelColor = MaterialTheme.colors.onSurface.copy(ContentAlpha.medium)
)
)
Related
I have a TextField with a fixed height. When the user enters a longer text it will scroll. It will cut off any text within the padding when scrolling:
Basically something like this:
var text by remember { mutableStateOf("") }
TextField(
value = text,
onValueChange = { value -> text = value },
modifier = modifier
.fillMaxWidth()
.height(100.dp),
colors = TextFieldDefaults.textFieldColors(
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
backgroundColor = Color.Transparent
)
)
It is possible to adjust/remove the padding for a TextField, by using BasicTextField directly, e.g. see this stack overflow question.
However I want to keep the padding, but without the clipping of the text when the user scrolls. A simple Text Composable has this behavior.
You can use BasicTextField and modify its decorationBox parameter.
Simply put innerTextField() inside a scrollable Column and add Spacers at the top and the bottom of it.
var text by remember {
mutableStateOf("Hello Stackoverflow")
}
val paddingSize = remember { 16.dp }
BasicTextField(
modifier = Modifier
.height(100.dp),
value = text,
onValueChange = { text = it },
decorationBox = { innerTextField ->
Column(
modifier = Modifier
.fillMaxWidth()
.verticalScroll(state = rememberScrollState())
) {
Spacer(modifier = Modifier.height(paddingSize))
innerTextField()
Spacer(modifier = Modifier.height(paddingSize))
}
}
)
Just use the maxLines parameter of the TextField to avoid clipping. Set it to 1 or 2, per your case, then adjust the height/font-size so the max lines you specify are accomodated correctly. It will likely start to snap to the visible portion, cutting the extra stuff entirely.
What I want:
I want my OutlinedTextField to be always focused or disable the ability to focus.
I want the OutlinedTextField to be RoundedCornerShape but when I use background it goes out of the shape.
My Code:
Column(modifier = Modifier
.weight(1f)
.background(Color.Gray)
.clip(RoundedCornerShape(35.dp))
) {
OutlinedTextField(
value = "12",
onValueChange = {},
readOnly = true,
shape = RoundedCornerShape(35.dp),
textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.End),
leadingIcon = { Icon(painter = painterResource(id = R.drawable.ic_coin), contentDescription = null)},
modifier = Modifier
)
}
Using enabled = false the text field will be neither editable nor focusable, the input of the text field will not be selectable, visually text field will appear in the disabled UI state readOnly.
To change the background color use the attribute backgroundColor in the TextFieldDefaults.outlinedTextFieldColors parameter:
OutlinedTextField(
value = "12",
onValueChange = {},
enabled = false,
shape = RoundedCornerShape(35.dp),
textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.End),
colors = TextFieldDefaults.outlinedTextFieldColors(
backgroundColor = Color.Gray,
disabledTextColor= LocalContentColor.current.copy(LocalContentAlpha.current),
)
)
If you want to wrap the component in a Column change the order of the modifiers:
Column(modifier = Modifier
.clip(RoundedCornerShape(35.dp))
.background(Color.Gray)
){
//....
}
If you want to change the border width you have to use the version 1.2.x and the OutlinedTextFieldDecorationBox specifying the border attribute:
BasicTextField(
//....
) {
OutlinedTextFieldDecorationBox(
border = {
TextFieldDefaults.BorderBox(
//...
unfocusedBorderThickness = 4.dp,
focusedBorderThickness = 4.dp
)
}
)
}
I have a LazyColumn consisting of text fields with numeric input. When I switch between text fields, I sometimes see a flicker. It first opens the normal text keyboard and then switches to numeric one. This is leading to a really bad UX.
My code:
LazyColumn {
items(payers) {
Row {
Image(...)
Text(...)
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp))
.padding(vertical = 4.dp)
) {
BasicTextField(
value = it.amount,
onValueChange = { /* Update it.amount */ },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
)
if (it.amount.isEmpty())
Text(
text = "₹ 0",
modifier = Modifier.alpha(0.5f)
)
}
}
}
}
Result:
How to avoid this flicker?
This looks like a known bug (specifically, that the keyboard type changes very quickly during focus request).
You can follow along on the bug tracker for updates.
When initially clicking the text field the whole view correctly shifts upwards so the keyboard is just below text entry.
After pressing return on the keyboard nothing on the screen moves and it leaves the cursor under the keyboard out of vision.
I had some other TextField issues that were solve by using the accompanist library. There is currently an assigned issue for it here. Here is the composable for the textField:
#Composable
fun EditTextContent(
label: String,
text: String,
isError: Boolean,
modifier: Modifier = Modifier,
singleLine: Boolean,
inputType: KeyboardType = KeyboardType.Text,
onTextChanged: (String) -> Unit
) {
val focusManager = LocalFocusManager.current
OutlinedTextField(
modifier = modifier.navigationBarsWithImePadding().testTag(label),
value = text,
onValueChange = {
onTextChanged(it)
},
label = { Text(label) },
singleLine = singleLine,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
keyboardOptions = KeyboardOptions(keyboardType = inputType),
isError = isError,
trailingIcon = {
if (isError) {
Icon(
painter = painterResource(id = R.drawable.ic_warning),
modifier = Modifier.size(25.dp),
contentDescription = null
)
} else {
null
}
},
)
}
Activity in the manifest is set to android:windowSoftInputMode="adjustPan" since adjustResize does nothing for some reason. Any help would be appreciated.
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
)
)
}