Request Focus in Jetpack compose in TextField

Viewed 561

This his how my composable looks like

@Composable
fun MyComposable(
 email:String?,
 onEmailChanged:(email)-> Unit,
 buttonClicked:()->Unit,
 validEmail:Boolean
){
    val focusRequester = remember { FocusRequester() }
    val focusManager = LocalFocusManager.current
    val keyboardController = LocalSoftwareKeyboardController.current

    TextField(
      modifier = Modifier
        .fillMaxWidth()
        .focusRequester(focusRequester = focusRequester),
      value = email ?: "",
      status = someStatus // Default, Error, Success
      onValueChange = { email -> onEmailChanged(email)},
    )
    Button(
      onClick = {
        focusManager.clearFocus()
        buttonClicked()
        if(!validEmail) focusRequester.requestFocus()
      },
    ) {
      Text(text = "Button")
    }
  }
}

I have added the basic code for explanation, i am facing issue with focusRequester when a button is clicked.

For accessibility reasons once the button is clicked, and if the email is invalid, i would like the focus to go back to TextField so that accessibility can announce it's state and label.

I tried clearing the focus and then requesting it again, but it only works for the first time. And i would like the TextField to gain focus every-time a button is clicked and email is invalid.

Am i missing something here?

2 Answers
  1. try this it works totally fine.

@Composable
fun Test() {
    val context = LocalContext.current
    val emailState = remember { mutableStateOf("") }
    val focusRequester = remember { FocusRequester() }
    val focusManager = LocalFocusManager.current

    Column {
        TextField(
            modifier = Modifier
                .focusRequester(focusRequester)
                .fillMaxWidth(),
            value = emailState.value,
            onValueChange = {
                emailState.value = it
            },
        )
        Button(onClick = {
            focusManager.clearFocus()
            if (emailState.value.isEmpty() ) {
                focusRequester.requestFocus()
                Toast.makeText(context, "error", Toast.LENGTH_SHORT).show()
            }
        }) { Text(text = "Button")
        }
    }
}

enter image description here

I couldn't find any way to get the focus back on TextField if it was already focused, once the button was clicked.

I ended up using live-region for announcement.

TextField(
      modifier = Modifier
        .fillMaxWidth()
        .semantics {
          liveRegion = LiveRegionMode.Assertive
        }),
      value = email ?: "",
      status = someStatus // Default, Error, Success
      onValueChange = { email -> onEmailChanged(email)},
    )
    Button(
      onClick = {
        focusManager.clearFocus()
        buttonClicked()
      },
    ) {
      Text(text = "Button")
    }
  }
Related