1

When user type in TextField it will call onValueChange{} callback. but when we set the value in TextField the onValueChange{} callback will not call.

I found https://issuetracker.google.com/issues/172239032 open issue.

Below is a code snippet where I have defined TextField.

OutlinedTextField(
        value = enteredValues[index],
        onValueChange = { value: String ->
            onTextFieldValueChange(value)
        },
        singleLine = true,
        keyboardOptions = keyboardOption,
        colors = textFieldColors,
    )

To get the callback of onValueChange I want to call the keypress event programmatically so might be I will get onValueChange callback. Can anyone give me a solution? how to use keypress programmatically in jetpack compose?

  • 1
    I didn't get your problem, please provide steps to reproduce it along with what do you expect from these steps – Phil Dukhov May 05 '22 at 11:20
  • I think you just need to call the same function used by `onValueChanged`... I mean, simply call `onTextFieldValueChange` will do the same thing as `onValueChanged`... – nglauber May 05 '22 at 20:00
  • "but when we set the value in TextField the onValueChange{} callback will not call.", of course it wont call the callback. The callback is called upon user interaction, not by the parameter change – Andra May 06 '22 at 05:26
  • @Andra Yes callback is called upon user interaction. I assume that we will get a callback on the call of the keypress event programmatically as it's already working in without using jetpack compose. So, there might be a case like using keypress we will get a callback. Please let me know in case have any solution or any other workaround. – Bhavin Vala May 06 '22 at 06:45

1 Answers1

1

I have no idea why you want to do this, but here it is a suggestion/workaround...

You can simulate the key event like below (credit for this answer):

fun simulateKeyPress(context: Context, key: Int) {
    val a = context as Activity
    a.window.decorView.rootView
    val inputConnection = BaseInputConnection(
        a.window.decorView.rootView,
        true
    )
    val downEvent = KeyEvent(KeyEvent.ACTION_DOWN, key)
    val upEvent = KeyEvent(KeyEvent.ACTION_UP, key)
    inputConnection.sendKeyEvent(downEvent)
    inputConnection.sendKeyEvent(upEvent)
}

Then, you can call this function passing the key code you want to send...

@Composable
fun SimulateKeySender() {
    var text by remember {
        mutableStateOf("")
    }
    val context = LocalContext.current
    val focusRequester = remember {
        FocusRequester()
    }
    Column {
        Button(
            onClick = { simulateKeyPress(context, KeyEvent.KEYCODE_A) }
        ) {
            Text(text = "Send A")
        }
        TextField(
            value = text,
            onValueChange = { text = it },
            modifier = Modifier.focusRequester(focusRequester)
        )
    }
    LaunchedEffect(Unit) {
        focusRequester.requestFocus()
    }
}

Notice that will only work if the TextField has focus, this is why I'm using the FocusRequester.

nglauber
  • 18,674
  • 6
  • 70
  • 75
  • There are legitimate use cases like creating a number pad or dialer where you want to pass the events from your custom dialpad to TextField and not want to deal with the complexities related to cursor position etc – M-Wajeeh Aug 17 '22 at 09:27