Coordinate nested scrolling
Consume an ancestor effect
Attach one stable NestedScrollConnection to the ancestor that owns the effect. Pre callbacks run
before child consumption; post callbacks receive what the child consumed and what remains. Return
only the signed distance or velocity actually consumed.
fun UiTreeBuilder.CollapsingToolbar(
collapseBy: (deltaY: Float) -> Float,
) {
val latestCollapseBy = rememberUpdatedState(collapseBy)
val connection = remember {
object : NestedScrollConnection {
override fun onPreScroll(
available: ScrollDelta,
source: NestedScrollSource,
): ScrollDelta {
return ScrollDelta(
x = 0f,
y = latestCollapseBy.value(available.y),
)
}
}
}
Column(modifier = Modifier.nestedScroll(connection)) {
Text("Collapsing toolbar")
ScrollableColumn {
repeat(40) { index -> Text("Row $index") }
}
}
}
Clamp application state inside collapseBy; the Android renderer also rejects non-finite or
over-consumed results. Use NestedScrollSource when user input, fling continuation, and imperative
side effects require different policy.
Dispatch a custom scroll source
Pass a stable NestedScrollDispatcher to nestedScroll when custom gesture or programmatic code
must enter the same parent chain. Dispatch pre-scroll first, consume the remainder locally, then
dispatch post-scroll with the local consumption and remainder. Use the equivalent pre/post fling
pair for velocity.
Lazy collections, pagers, eager scroll containers, PullToRefresh, and framework drag or transform
pan participate in the same chain. A native AndroidView joins automatically only when its View
implements Android nested scrolling; otherwise dispatch explicitly. See
Modifier architecture for phase order, modifier ordering, AndroidX
mapping, and the legacy native-fling limitation.