2

I have a custom component in my Compose Desktop app, which can have the focus:

val focusRequester = remember { FocusRequester() }
var focused by remember { mutableStateOf(false) }
Row(modifier.fillMaxWidth()
    .focusRequester(focusRequester)
    .onFocusChanged { state -> focused = state.isFocused }

This works as you'd expect. However, when I add a border based on focused state, it breaks:

val focusRequester = remember { FocusRequester() }
var focused by remember { mutableStateOf(false) }
Row(Modifier.fillMaxWidth()
    .focusRequester(focusRequester)
    .onFocusChanged { state -> focused = state.isFocused }
    .border(if (focused) 1.dp else 0.dp, MaterialTheme.colors.primary)

From what I can tell, the recompose actually causes the onFocusedChanged to fire again with isFocused = false. So that's the problem, not the remembering of the focused property itself.

How can my component keep the focus after recomposing to draw the border?

Jorn
  • 20,612
  • 18
  • 79
  • 126
  • What do you mean by "it breaks"? Please provide a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). – Phil Dukhov Apr 13 '22 at 08:33
  • 1
    @PylypDukhov That is explained in the second to last paragraph. If it's not clear, please be specific so I can update the question. – Jorn Apr 13 '22 at 08:35

1 Answers1

2

You can use interactionSource.collectIsFocusedAsState() instead of the onFocusChanged modifier.

Something like:

val focusRequester = remember { FocusRequester() }
val interactionSource = remember { MutableInteractionSource() }
val focused by interactionSource.collectIsFocusedAsState()

    Row(Modifier
         // add focusRequester modifier before the focusable (or even in the parent)
        .focusRequester(focusRequester)
        .focusable(interactionSource = interactionSource)
        .border(if (focused) 1.dp else 0.dp, MaterialTheme.colors.primary)
Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841