Show trailing icon after text input from user in TextField Jetpack Compose - android

I am trying to:
make the trailingIcon of TextField composable visible only if the user enters some text other than white spaces.
Later when the user clicks the trailingIcon the text in the TextField should get cleared and the trailingIcon should disappear.
Again when the user enters a text other than space, the trailingIcon should appear and enable this text clearing feature.
and so on...
I tried searching for solutions to this problem but mostly they were focused on "visible trailingIcons" and not what I was trying to implement.

Depending on text state you can specify null or actual view for trailingIcon parameter:
var text by remember { mutableStateOf("") }
val trailingIconView = #Composable {
IconButton(
onClick = {
text = ""
},
) {
Icon(
Icons.Default.Clear,
contentDescription = "",
tint = Color.Black
)
}
}
TextField(
value = text,
onValueChange = { text = it },
trailingIcon = if (text.isNotBlank()) trailingIconView else null,
)

You can add a condition to make visible the trailingIcon.
Something like:
var text by remember { mutableStateOf("") }
val isVisible by remember {
derivedStateOf {
text.isNotBlank()
}
}
OutlinedTextField(
value = text,
onValueChange = {
text = it
},
trailingIcon = {
if (isVisible) {
IconButton(
onClick = { text = "" }
) {
Icon(
imageVector = Icons.Default.Clear,
contentDescription = "Clear"
)
}
}
}
)

Related

How to set a OutlinedTextField occupy the remaining space Jetpack Compose?

I want to create a top app bar that contains a back icon and a search. Here is what I have tried.
SmallTopAppBar(
title = {
Text(
text = "MyApp"
)
},
navigationIcon = {
IconButton(
onClick = navController.popBackStack()
) {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = null
)
}
},
actions = {
OutlinedTextField(
modifier = Modifier.fillMaxWidth(1f) //Here is the issue.
.padding(2.dp)
value = search,
maxLines = 1,
singleLine = true
)
}
)
The problem comes when I try to use .fillMaxWidth(1f), it doesn't take only the remaining space, but it get over the arrow button?
This is what I expect:
How to solve this?
You can put the OutlinedTextField inside the title attribute instead of the actions attribute
SmallTopAppBar(
title = {
OutlinedTextField(
value = text,
onValueChange = {text = it},
modifier = Modifier.fillMaxWidth(1f)
.padding(2.dp),
maxLines = 1,
singleLine = true
)
},
navigationIcon = {
//IconButton
},
actions = {
//IconButton
}
)

Compose TextField with number keypad by default, but allowing alphabetic characters

I want to show a numeric keyboard by default but let the user change it to text.
var text by rememberSaveable { mutableStateOf("") }
TextField(
value = text,
onValueChange = { text = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
)
I read a lot of old questions and answers but none of them were helpful, including:
How do I default to numeric keyboard on EditText without forcing numeric input?
EditText with number keypad by default, but allowing alphabetic characters
There is no straightforward solution. So, I decided to implement it myself:
var keyboardType by remember { mutableStateOf(KeyboardType.Number) }
var text by rememberSaveable { mutableStateOf("") }
TextField(
value = text,
onValueChange = { text = it },
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = keyboardType),
trailingIcon = {
if (keyboardType == KeyboardType.Number) {
Icon(
painterResource(
id = if (keyboardType == KeyboardType.Number)
R.drawable.ic_abc_24
else
R.drawable.ic_pin_24
),
contentDescription = "Change keyboard",
modifier = Modifier.clickable {
keyboardType = if (keyboardType == KeyboardType.Number)
KeyboardType.Text
else
KeyboardType.Number
}
)
}
}
)

Remove keypad along with ModalBottomSheetLayout in Jetpack compose

After clicking outside BottomSheet, BottomSheet is hidden but the keypad remains persistent.
I want to remove the keypad as soon as BottomSheet is hidden in ModalBottomSheetLayout
After clicking the text in compose keypad pops up
After clicking outside bottom sheet, bottom sheet disappears but keypad persists
val state = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)
val scope = rememberCoroutineScope()
ModalBottomSheetLayout(
sheetContent = {
Column {
var text by remember { mutableStateOf("") }
OutlinedTextField(
value = text,
label = { Text("Text") },
onValueChange = { text = it }
)
var text1 by remember { mutableStateOf("") }
OutlinedTextField(
value = text1,
label = { Text("Text1") },
onValueChange = { text1 = it }
)
OutlinedButton(
onClick = { click() },
) { Text(text = "SUBMIT") }
}
},
sheetState = state,
content = {
Greeting(state = state, scope = scope)
}
)
You need to add keyboard options and actions for the text fields. The keyboard options setup what type of keyboard and action you have on the keyboard. The onAction you pass the lambda to hide the bottom sheet and clear the focus:
val sheetState = rememberModalBottomSheetState(
skipHalfExpanded = true,
initialValue = ModalBottomSheetValue.Hidden
)
val focusRequester = remember { FocusRequester() }
OutlinedTextField(
value = text,
label = { Text("Text") },
onValueChange = { text = it },
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = {
coroutineScope.launch {
focusRequester.freeFocus()
sheetState.hide()
}
}
)
)

Jetpack compose TextField soft keyboard obscures text entry

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.

Get Button Text

I have a Button composable that I need to get the text value when clicked.
Button(
onClick = {// Get the "TheText" from below },
) {
Text(
modifier = Modifier.padding(8.dp),
text = "TheText",
style = TextStyle(fontSize = 15.sp)
)
}
I am creating a type of quiz where the buttons text matches the correct answer.
I thin I may need to create a custom compposabe that takes the text as a parameter and also a callback function that will pass that text back up to my main program where I can Check for a correct answer.
I assume you want to input text instead of just displaying one.
#Composable
fun example() {
var text by remember { mutableStateOf("TheText") }
Column {
Button(
onClick = {
val useThisString = text
},
) { Text(text = text) } // Probably wanna put "Copy" here
TextField(
value = text,
onValueChange = { text = it },
label = { Text("Optinal Label") }
)
}
}
Otherwise, if you just want the label of the button:
val buttonText = "TheText"
Button(
onClick = {
// Use variable here
},
) {
Text(
modifier = Modifier.padding(8.dp),
text = buttonText,
style = TextStyle(fontSize = 15.sp)
)
}
Ok here's how to store it in a variable
var retrievedValue by mutableStateOf("") //Assuming you must use it somewhere else as state
var currentValue by rememberSaveable { mutableStateOf("The Text") }
Button(
onClick = { retrievedValue = currentValue },
) {
Text(
modifier = Modifier.padding(8.dp),
text = currentValue,
style = TextStyle(fontSize = 15.sp)
)
}
Now you can use it anywhere you want. Changing the retrievedValue would trigger recompositions in any composable that reads it.
This should solve your problem. Use the retrievedValue as the value returned by a callback. In compose, for such stuff, you do not need callbacks. MutableState objects, whenever are modified, trigger a recomposition on the composables reading them.
Anyway, here when you click the button, you will get the value of the text, whatever it may be, you will always get the current value.

Categories

Resources