Focus management in Jetpack Compose

Introduction to the

Focus management in Jetpack Compose is a bit different from traditional View systems, and while it’s not often used, it’s hard to know how to use it. Compose Compose Compose Compose Compose Compose Compose Compose Compose Compose Compose Compose Compose Compose Compose Compose

Because I am also learning while writing this article, so there may be mistakes, welcome to correct. 🤗

What is the focus

Focus may not be common on a phone, but it’s still common on a TV, and it’s important when using the remote to manipulate the UI. The user operates by moving the focus selection control up, down, left, and right with the remote control.

As for mobile phones, focus is usually used to move the focus of the input box when the user is typing.

Quick learning

1. Move the focus

The simplest requirement to manipulate focus is to move focus, such as to the next input box

First we need to get a FocusManager by:

val focusManager = LocalFocusManager.current
Copy the code

Focusmanager.movefocus () is then called to move the focus when it needs to be moved, passing in the direction argument to specify which direction to move the focus in, for example, to the right:

focusManager.moveFocus(FocusDirection.Right)
Copy the code

2. Add focus

If you want to add focus to your own control, you can use Modifier. Focusable () to add focus to the control, for example:

Box(
  modifier = Modifier
    .focusable()
    .size(400.dp)
){
  Text("Hello World!")}Copy the code

Thus, the Box is focusable

Note: some of the Compose controls that already require a focus already have a focus. Please do not add a focus to them such as TextField

3. Listen for changes in focus

Very simple, use Modifier. OnFocusChanged or Modifier. OnFocusEvent, the two are almost the same, the difference is that onFucusChanged will determine whether the status has really changed and then notify you, while onFucusEvent will not determine.

Here’s an example:

TextField(
  value = ...
  onValueChange = { .. }
  modifier = Modifier.onFocusChanged {
    when {
        it.isFocused -> // I am in focus
        it.hasFocused -> // My subterm is focused
        it.isCaptured -> // Whether it is in the capture state}}Copy the code

Capture: After a focus is focused, it can also be set to capture. In the capture state, other components cannot request focus until it is actively released

Tip: onFucusChanged is also internally based on onFucusEvent

4. Set the focus order

Focusmanager.movefocus () can be used to move the focus by focusmanager.movefocus (), which is composed’s order. For example, the Modifier, focusOrder() should be used to define the focusOrder.

// First we get two new focus references, representing two different focus points (using Kotlin's deconstruction feature here)
val (cat, dog) = FocusRequester.createRefs()

Box(
  modifier = Modifier
  .focusOrder(cat) { // The cat reference is passed in
    next = dog // Set cat's next focus to dog
    down = dog // Set the focus under cat to dog
    // ..
  }
  .focusable() // Settings can be focused
)

Box(
  modifier = Modifier
  .focusOrder(dog) {
    previous = cat // Set the Angle above dog to cat
    up = cat // Set the focus on dog to cat
  }
  .focusable() // Settings can be focused
)
Copy the code

Does this look a lot like the constraint layout API in Compose? Ha ha

Note:focusable()Must be put in other focus Modifier behind, otherwise will not work! For example, focusable() needs to be placed under focusOrder. Because the Modifier uses the box model, other focus modifiers placed outside the Focusable focus will not get the focus information.

5. Request focus programmatically directly

Moving focus with FocusManager may still not work in some cases, and we may need to request a specific focus directly. Set the focus request reference and call the focus reference to request the focus:

/ / new a FocusRequester directly here, because FocusRequester. CreateRefs inside () is a new instance of this class
val requester = FocusRequester()

Box(
    modifier = Modifier
    .focusOrder(requester)
    .focusable()
)

SideEffect {
  // Request the focus of Box directly after the reorganization is complete
  requester.requestFocus()
}

Copy the code

Other FocusRequester apis:

  • freeFocusRelease the captured focus
  • captureFocusCapture focus (neededrequestFocus()Call when you get focus)