If you want your Jetpack Compose elements to handle focus directly (e.g., using Modifier.onFocusChanged or Modifier.focusable()), use DpadComposeFocusViewHolder. This ViewHolder passes the focus state directly into the Composable tree.
To implement this:
- Create a
ListAdapter using DpadComposeFocusViewHolder<T> as the ViewHolder type. - In
onCreateViewHolder, provide a lambda that defines how to render the Composable. - In
onBindViewHolder, call holder.setItemState(item) to update the content. - Inside your Composable, use standard focus modifiers like
.onFocusChanged { ... } and .focusable() to react to focus changes.
class ComposeItemAdapter(
private val onItemClick: (Int) -> Unit
) : ListAdapter<Int, DpadComposeFocusViewHolder<Int>>(Item.DIFF_CALLBACK) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): DpadComposeFocusViewHolder<Int> {
return DpadComposeFocusViewHolder(parent) { item ->
ItemComposable(
item = item,
onClick = {
onItemClick(item)
}
)
}
}
override fun onBindViewHolder(
holder: DpadComposeFocusViewHolder<Int>,
position: Int
) {
holder.setItemState(getItem(position))
}
}
@Composable
fun ItemComposable(
item: Int,
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
var isFocused by remember { mutableStateOf(false) }
val backgroundColor = if (isFocused) Color.White else Color.Black
val textColor = if (isFocused) Color.Black else Color.White
Box(
modifier = modifier
.background(backgroundColor)
.onFocusChanged { focusState ->
isFocused = focusState.hasFocus
}
.focusable()
.dpadClickable {
onClick()
},
contentAlignment = Alignment.Center,
) {
Text(
text = item.toString(),
color = textColor,
fontSize = 35.sp
)
}
}