How would you go about testing what input type TextField uses, for example if I wanted to test if user input has an alphanumeric keyboard type or numeric.
I can see that in SemanticProperties there is ImeAction, but I can't see anything I could use to check KeyboardOptions that you set in TextField.
You can use something like:
val platformTextInputService = mock<PlatformTextInputService>()
val textInputService = TextInputService(platformTextInputService)
composeRule.setContent {
CompositionLocalProvider(
LocalTextInputService provides textInputService
) {
val text = remember { mutableStateOf("") }
TextField(
modifier = Modifier.testTag(TextfieldTag),
value = text.value,
onValueChange = { text.value = it },
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number
)
)
}
}
composeRule.onNodeWithTag(TextfieldTag).performClick()
composeRule.runOnIdle {
verify(platformTextInputService, atLeastOnce()).startInput(
value = any(),
imeOptions = eq(
ImeOptions(
keyboardType = KeyboardType.Number,
)
),
onEditCommand = any(),
onImeActionPerformed = any()
)
}
I have textField composable and button composable. I want that clicking at the button would erase the text in the textField composable.
example:
var text by remember
mutableStateOf(TextFieldValue(""))}
TextField(
value = text,
onValueChange = { newValue -> text = newValue },
modifier = Modifier
.padding(8.dp),
)
Button(
onClick = {
//TODO: clean the text in textFiled
},
modifier = Modifier
.size(200.dp, 40.dp)
) {
Text(text = "erase textField"
}
thanks
You can just simply reset the value of the text mutableState:
Button(onClick = { text = TextFieldValue("") })
Create a mutableState as follows -> var textState by remember { mutableStateOf("") }
Create Textfield -> TextField(value = textState, onValueChange = { textState = it })
In the onClick of the button invoke the textState -> textState = ""
I am trying to type text into a text field in interactive mode and it's not working. But, doing it on a physical device works.
MainActivity.kt
#Preview(showSystemUi = true)
#Composable
fun HelloContentPreview()
{
HelloContent()
}
#Composable
fun HelloContent()
{
Column(modifier = Modifier.padding(16.dp)) {
var name by remember { mutableStateOf("") }
Text(
text = "Hello! $name",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
OutlinedTextField(
value = name,
onValueChange = {
name = it
Log.i(TAG, "HelloContent: onValueChange: $it")
},
label = { Text("Name") }
)
}
}
Interactive mode
The bug is fixed, it now works in Electric Eel.
I'd like to have a TextField bound to a MutableStateFlow that comes from a view model. This is how I set it up:
#Composable
fun MyTextField(textFlow: MutableStateFlow<String>) {
val state = textFlow.collectAsState(initial = "")
TextField(
value = TextFieldValue(state.value),
onValueChange = { textFlow.value = it.text },
label = { Text(text = "Label") }
)
}
When I type something into the text field, it behaves really strangely. For example, if I type 'asd', it ends up with 'asdasa'. How can I update textFlow.value without messing up with the text field?
This error is caused by the usage of TextFieldValue with Flow.
To fix this, set the value of the TextField to just state.value and then on text change set the value with textFlow.value = it.
#Composable
fun MyTextField(textFlow: MutableStateFlow<String>) {
val state = textFlow.collectAsState(initial = "")
TextField(
value = state.value,
onValueChange = { textFlow.value = it },
label = { Text(text = "Label") }
)
}
I'm using the Jetpack Compose TextField and I want to close the virtual keyboard when the user press the the action button (imeActionPerformed parameter).
val text = +state { "" }
TextField(
value = text.value,
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Done,
onImeActionPerformed = {
// TODO Close the virtual keyboard here <<<
}
onValueChange = { s -> text.value = s }
)
You can use the LocalSoftwareKeyboardController class to control the current software keyboard and then use the hide method:
var text by remember { mutableStateOf(TextFieldValue("Text")) }
val keyboardController = LocalSoftwareKeyboardController.current
TextField(
value = text,
onValueChange = {
text = it
},
label = { Text("Label") },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(
onDone = {keyboardController?.hide()})
)
This solution closes the keyboard without removing the focus from the current TextField.
Just to highlight the difference with:
val focusManager = LocalFocusManager.current
focusManager.clearFocus()
This code closes the keyboard removing the focus from the TextField.
Starting from compose 1.0.0-alpha12 (and still valid in compose 1.3.1) the onImeActionPerformed is deprecated and suggested approach is to use keyboardActions with combination of keyboardOptions:
val focusManager = LocalFocusManager.current
OutlinedTextField(
value = ...,
onValueChange = ...,
label = ...,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done, keyboardType = KeyboardType.Password),
)
focusManager.clearFocus() will take care of dismissing the soft keyboard.
In 1.0.0 you can either use SoftwareKeyboardController or FocusManager to do this.
This answer focuses on their differences.
Setup:
var text by remember { mutableStateOf("")}
TextField(
value = text,
onValueChange = { text = it },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { /* TODO */ }),
)
SoftwareKeyboardController:
Based on #Gabriele Mariottis answer.
val keyboardController = LocalSoftwareKeyboardController.current
// TODO =
keyboardController?.hide()
This only closes the keyboard, but does NOT clear the focus from any focused TextField (note the cursor & thick underline).
FocusManager:
Based on #azizbekians answer.
val focusManager = LocalFocusManager.current
// TODO =
focusManager.clearFocus()
This closes the keyboard AND clears the focus from the TextField.
Hiding the keyboard on button click
To add with Gabriele Mariotti's solution, if you want to hide the keyboard conditionally, say after a button click, use this:
keyboardController?.hide()
For example, hide the keyboard after clicking the Add button:
var newWord by remember { mutableStateOf("") }
val keyboardController = LocalSoftwareKeyboardController.current
// Setup the text field with keyboard as provided by Gabriele Mariotti
...
Button(
modifier = Modifier
.height(56.dp),
onClick = {
if (!newWord.trim().isNullOrEmpty()) {
wordViewModel.onAddWord(newWord.trim())
newWord = ""
keyboardController?.hide()
}
...
Edit after alpha-12 release:
See #azizbekian response.
Pre-alpha-12 response
I found the solution here :)
fun hideKeyboard(activity: Activity) {
val imm: InputMethodManager = activity.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
var view = activity.currentFocus
if (view == null) {
view = View(activity)
}
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
I just need to call the function above from my component:
// getting the context
val context = +ambient(ContextAmbient)
// textfield state
val text = +state { "" }
TextField(
value = text.value,
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Done,
onImeActionPerformed = {
if (imeAction == ImeAction.Done) {
hideKeyboard(context as Activity)
}
}
onValueChange = { s -> text.value = s }
)
I found a way to shut him down in the CoreTextField,use TextInputService to control the switch
val focus = LocalTextInputService.current
var text by remember{ mutableStateOf("")}
TextField(
value = text,
onValueChange = { text = it },
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done, keyboardType = KeyboardType.Text),
keyboardActions = KeyboardActions(onDone = { focus?.hideSoftwareKeyboard() }),
singleLine = true
)
implementation 'androidx.compose.material3:material3:1.0.0-alpha02'
Text Field With Hide Keyboard On Ime Action
#OptIn(ExperimentalComposeUiApi::class)
#Composable
fun TextFieldWithHideKeyboardOnImeAction() {
val keyboardController = LocalSoftwareKeyboardController.current
var text by rememberSaveable { mutableStateOf("") }
TextField(
value = text,
onValueChange = { text = it },
label = { Text("Label") },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(
onDone = {
keyboardController?.hide()
// do something here
}
)
)
}