I’m having an issue with TextField. If I have a Te...
# compose
b
I’m having an issue with TextField. If I have a TextField like this:
Copy code
@ExperimentalComposeUiApi
@Composable
fun UsernameTextField(
    state: State<String>,
    label: String,
    onValueChange: (String) -> Unit
) {
    Column {
        TextField(
            value = state.value,
            onValueChange = onValueChange,
            label = { Text(label) },
            modifier = Modifier
                .fillMaxWidth()
                .padding(16.dp),
            singleLine = true
        )
    }
}
and call it like this:
Copy code
UsernameTextField(
    state = userName,
    label = getString(R.string.Username),
) {
    loginViewModel.updateUserName(it)
}
When typing most characters, the
onValueChange
is triggered on the whole String there, like “a”, “ad”, “ada”. But if I type a tab or return at the end of a String,
onValueChange
is triggered on only the tab/return character. Does anyone understand why this is happening?
🤔 1
z
Are you using a hardware keyboard?
I wonder if it’s related to this
b
I’m using an emulator and typing on a keyboard. Does that count?
That issue is exactly what I’m running into.
z
is it gboard?
b
Yes
z
Seems like a useful data point – i’d comment on that issue with your repro details
d
This is exactly what I was seeing!
The virtual IME works but the hardware does not. I wonder if the non GBoard keyboards send commands like a hardware one and that is why they do not work either.
b
Yeah, it’s pretty strange. I was able to approximate how it should behave by just moving focus to the next TextField when a tab is pressed, but I have no idea how it works. It really shouldn’t work. I’m using the same FocusRequester for both TextFields, and calling request focus on a Tab key event, and adding an IME Action to both (Next for the first one, Done for the second).
d
@Brady Aiello I think I have devised a work around but need a chance to code it up. If it works I could share it with you.
The idea is to cache the previous copy of the text value and then detect tabs or new lines in the latest copy. If there is a new line or tab just use the previous copy and shift the focus to the next field.
b
Yeah, that’s essentially what I’m doing now.
The tricky part is changing focus, ie. in an emulator, navigating to the next TextField on a tab press. Doing text validation like this:
Copy code
val userName = MutableStateFlow("")

fun updateUserName(userName: String) {
    val temp = userName.filterNot { it.isWhitespace() }
    if (temp.isNotEmpty()) {
        this.userName.value = temp
    } else if (userName == "") {
        this.userName.value = ""
    }
}
d
Copy code
val userName = mutableStateOf(TextFieldValue(text = ""))

fun updateUserName(nextName: TextFieldValue) {
    val bad = nextName.text.firstOrNull { it.isWhitespace() && it != ' ' } != null
    if (bad) {
        shiftFocus()
    } else {
        this.userName.value = nextName
    }
}
I was thinking more along the lines of this.
👍 1
s
But if I type a tab or return at the end of a String, 
onValueChange
  is triggered on only the tab/return character
This sounds like a bug, and I didnt understand how it would happen, please create a bug or add info to the bug Zach mentioned.
Moving focus on tab: you should catch the tab yourself and change the focus imho, rather than relying on TextField.
Also one questions about “`onValueChange`  is triggered on only the tab/return character” Can you elaborate on triggered on only ? Is it that the value passed to onValueChange is only tab character rather than the whole string?
d
yes only the tab character and not the whole thing.