The configuration of how a scrollable reacts to bring into view requests.
@ExperimentalFoundationApi
@Composable
fun FocusScrollingInLazyRowSample() {
// a bring into view spec that pivots around the center of the scrollable container
val customBringIntoViewSpec =
object : BringIntoViewSpec {
override fun calculateScrollDistance(
offset: Float,
size: Float,
containerSize: Float,
): Float {
val trailingEdgeOfItemRequestingFocus = offset + size
val sizeOfItemRequestingFocus = abs(trailingEdgeOfItemRequestingFocus - offset)
val childSmallerThanParent = sizeOfItemRequestingFocus <= containerSize
val initialTargetForLeadingEdge =
containerSize / 2f - (sizeOfItemRequestingFocus / 2f)
val spaceAvailableToShowItem = containerSize - initialTargetForLeadingEdge
val targetForLeadingEdge =
if (
childSmallerThanParent &&
spaceAvailableToShowItem < sizeOfItemRequestingFocus
) {
containerSize - sizeOfItemRequestingFocus
} else {
initialTargetForLeadingEdge
}
return offset - targetForLeadingEdge
}
}
// LocalBringIntoViewSpec will apply to all scrollables in the hierarchy.
CompositionLocalProvider(LocalBringIntoViewSpec provides customBringIntoViewSpec) {
LazyRow(modifier = Modifier.fillMaxWidth().wrapContentHeight()) {
items(100) {
var color by remember { mutableStateOf(Color.White) }
Box(
modifier =
Modifier.size(100.dp)
.padding(4.dp)
.background(Color.Gray)
.onFocusChanged { color = if (it.isFocused) Color.Red else Color.White }
.border(5.dp, color)
.focusable(),
contentAlignment = Alignment.Center,
) {
Text(text = it.toString())
}
}
}
}
}