[hierarchicalFocusGroup] is used to annotate composables in an application, so we can keep track of what is the active part of the composition.
HierarchicalFocus2Levels
@Composable
fun HierarchicalFocus2Levels() {
Column(Modifier.fillMaxSize()) {
var selectedRow by remember { mutableIntStateOf(0) }
repeat(2) { rowIx ->
Row(
Modifier.weight(1f)
.fillMaxWidth()
.hierarchicalFocusGroup(active = selectedRow == rowIx)
) {
var selectedItem by remember { mutableIntStateOf(0) }
repeat(2) { itemIx ->
Box(
Modifier.weight(1f).hierarchicalFocusGroup(active = selectedItem == itemIx)
) {
// ScalingLazyColumn uses requestFocusOnHierarchyActive internally
ScalingLazyColumn(
Modifier.fillMaxWidth().clickable {
selectedRow = rowIx
selectedItem = itemIx
}
) {
val prefix = (rowIx * 2 + itemIx + 'A'.code).toChar()
items(20) {
BasicText(
"$prefix $it",
style =
TextStyle(
color = Color.White,
fontSize = 20.sp,
textAlign = TextAlign.Center,
),
)
}
}
}
}
}
}
}
}
HierarchicalFocusSample
@Composable
fun HierarchicalFocusSample() {
var selected by remember { mutableIntStateOf(0) }
Row(Modifier.fillMaxSize(), verticalAlignment = Alignment.CenterVertically) {
repeat(5) { colIx ->
Box(
Modifier.hierarchicalFocusGroup(active = selected == colIx)
.weight(1f)
.clickable { selected = colIx }
.then(
if (selected == colIx) {
Modifier.border(BorderStroke(2.dp, Color.Red))
} else {
Modifier
}
)
) {
// This is used a Gray background to the currently focused item, as seen by the
// focus system.
var focused by remember { mutableStateOf(false) }
BasicText(
"$colIx",
style =
TextStyle(
color = Color.White,
fontSize = 20.sp,
textAlign = TextAlign.Center,
),
modifier =
Modifier.fillMaxWidth()
.requestFocusOnHierarchyActive()
.onFocusChanged { focused = it.isFocused }
.focusable()
.then(
if (focused) {
Modifier.background(Color.Gray)
} else {
Modifier
}
),
)
}
}
}
}