Jetpack Compose Number Input in to TextField - android

I am currently unable to capture user input in to a textfield when the KeyboardType of the keyboard is set to KeyboardType.Number.
If the keyboard is set to KeyboardType.Text, the Textfield updates as expected, however when set to KeyboardType.Number, the Textfield fails to update.
Why is this? and how can I change my code so that when the Textfield is clicked, a Number Keyboard is displayed ,and, when numbers are pressed, the relevant numbers are updated in the Textfield.
The following code DOES NOT update the textfield (When set to KeyboardType.Number)...
#Composable
fun MyNumberField() {
var text = remember { mutableStateOf("")}
val change : (String) -> Unit = { it ->
value.value = it
}
TextField(
value = text.value,
modifier = Modifier.fillMaxWidth(),
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number),
onValueChange = change
)
}
The following code does update the textfield (When set to KeyboardType.Text)...
#Composable
fun MyNumberField() {
var text = remember { mutableStateOf("")}
val change : (String) -> Unit = { it ->
text.value = it
}
TextField(
value = value.value,
modifier = Modifier.fillMaxWidth(),
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Text),
onValueChange = change
)
}
Many Thanks

You are supposed to update text.value, not value.value there is a typo in your code change it to this.
#Composable
fun MyNumberField() {
var text = remember { mutableStateOf("")}
val change : (String) -> Unit = { it ->
value.value = it // you have this which is not correct and I don't think it even compiled
text.value = it // it is supposed to be this
}
TextField(
value = text.value,
modifier = Modifier.fillMaxWidth(),
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number),
onValueChange = change
)
}

Related

Android compose test TextField input type

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

how can one composable change other composable value

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 = ""

Unable to type text in interactive mode in Jetpack Compose

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.

TextField with Kotlin StateFlow

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

How to close the virtual keyboard from a Jetpack Compose TextField?

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

Categories

Resources