Provide visual cues for easier focus visualization
While all the focusable elements from Material Theme already have a focus style that matches the theme, you might need to add some visual elements to make the focused element easier to spot. A good solution would be to change the border of your element with a color that has a good contrast with the background:
var color by remember { mutableStateOf(Color.White) } Card( modifier = Modifier .onFocusChanged { color = if (it.isFocused) Red else White } .border(5.dp, color) ) {}
In this example, remember
is used to store the color of the border across
recompositions, and the outline of the element is updated every time the element
gains or loses focus.
Implement advanced visual cues
With Jetpack Compose, you can also create more sophisticated and advanced visual cues that match better with your UI.
- First, create an
IndicationInstance
that visually draws the cue you want in your UI:private class MyHighlightIndicationInstance(isEnabledState: State<Boolean>) : IndicationInstance { private val isEnabled by isEnabledState override fun ContentDrawScope.drawIndication() { drawContent() if (isEnabled) { drawRect(size = size, color = Color.White, alpha = 0.2f) } } }
- Next, create an
Indication
and remember the focused state:class MyHighlightIndication : Indication { @Composable override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance { val isFocusedState = interactionSource.collectIsFocusedAsState() return remember(interactionSource) { MyHighlightIndicationInstance(isEnabledState = isFocusedState) } } }
- Add both the
Indication
and anInteractionSource
to the UI, via theindication()
modifier:val highlightIndication = remember { MyHighlightIndication() } var interactionSource = remember { MutableInteractionSource() } Card( modifier = Modifier .clickable( interactionSource = interactionSource, indication = highlightIndication, enabled = true, onClick = { } ) ) {}
Understand the state of the focus
Generally, every time a state of the focus changes, a FocusEvent
is fired up
the tree, and the parents of a focusable()
modifier can listen to it using the
onFocusChanged()
modifier.
If you need to know the state of the focus,you can use these APIs in conjunction
with the onFocusChanged
modifier:
isFocused
returnstrue
if the composable to which the modifier is attached is focusedhasFocus
works similarly toisFocused
, but with a substantial difference: rather than checking only the current, it checks if the element or one of its children is focusedisCaptured
returnstrue
whenever the focus is held. This happens, for instance, when aTextField
contains incorrect data, so that trying to focus other elements will not clear the focus.
These fields are shown below:
Modifier.onFocusChanged {
val isFocused = it.isFocused
val hasFocus = it.hasFocus
val isCaptured= it.isCaptured
}
Recommended for you
- Note: link text is displayed when JavaScript is off
- Change focus behavior
- Material Design 2 in Compose
- Handle user input