Explanation of how gesture system in Jetpack Compose works in detail here and here
change.consumeAllChanges()
is deprecated now, partial consumes are deprecated. change.consume()
is the only consume function to be used. What consume does is it returns change.isConsumed
true and because of that any drag, scroll, transform gesture stops progressing or receiving events. detectDragGestures and detectTransformGestures consume events by default so next
Modifier.pointerInput()
doesn't get these events. What you commented doesn't mean anything since drag already consumes events.
Here it's source code.
suspend fun PointerInputScope.detectDragGestures(
onDragStart: (Offset) -> Unit = { },
onDragEnd: () -> Unit = { },
onDragCancel: () -> Unit = { },
onDrag: (change: PointerInputChange, dragAmount: Offset) -> Unit
) {
forEachGesture {
awaitPointerEventScope {
val down = awaitFirstDown(requireUnconsumed = false)
var drag: PointerInputChange?
var overSlop = Offset.Zero
do {
drag = awaitPointerSlopOrCancellation(
down.id,
down.type
) { change, over ->
change.consume()
overSlop = over
}
// ! EVERY Default movable GESTURE HAS THIS CHECK
} while (drag != null && !drag.isConsumed)
if (drag != null) {
onDragStart.invoke(drag.position)
onDrag(drag, overSlop)
if (
!drag(drag.id) {
onDrag(it, it.positionChange())
it.consume()
}
) {
onDragCancel()
} else {
onDragEnd()
}
}
}
}
}
What you can do is using nestedScroll on parent of LazyColumn as here
@Composable
private fun NestedScrollExample() {
var text by remember { mutableStateOf("") }
val nestedScrollConnection = remember {
object : NestedScrollConnection {
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
text = "onPreScroll()\n" +
"available: $available\n" +
"source: $source\n\n"
return super.onPreScroll(available, source)
}
override fun onPostScroll(
consumed: Offset,
available: Offset,
source: NestedScrollSource
): Offset {
text += "onPostScroll()\n" +
"consumed: $consumed\n" +
"available: $available\n" +
"source: $source\n\n"
return super.onPostScroll(consumed, available, source)
}
override suspend fun onPreFling(available: Velocity): Velocity {
text += "onPreFling()\n" +
" available: $available\n\n"
return super.onPreFling(available)
}
override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
text += "onPostFling()\n" +
"consumed: $consumed\n" +
"available: $available\n\n"
return super.onPostFling(consumed, available)
}
}
}
Column() {
Box(
Modifier
.weight(1f)
.nestedScroll(nestedScrollConnection)
) {
LazyColumn(
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items(100) {
Text(
text = "I'm item $it",
modifier = Modifier
.shadow(1.dp, RoundedCornerShape(5.dp))
.fillMaxWidth()
.background(Color.LightGray)
.padding(12.dp),
fontSize = 16.sp,
color = Color.White
)
}
}
}
Spacer(modifier = Modifier.height(10.dp))
Text(
text = text,
modifier = Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())
.height(250.dp)
.padding(10.dp)
.background(BlueGrey400),
fontSize = 16.sp,
color = Color.White
)
}
}

It will return if you scroll up or down on your LazyColumn, if you want to do this only when your items are being scrolled you can do it as
Column(modifier = Modifier.fillMaxSize()) {
var text by remember { mutableStateOf("Drag to see effects") }
Text(text)
LazyColumn {
items(100) {
Text(
text = "Item $it",
fontSize = 24.sp,
textAlign = TextAlign.Center,
modifier = Modifier
.border(3.dp, Color.Green)
.fillMaxSize()
.padding(vertical = 24.dp)
.pointerMotionEvents(Unit,
onDown = {
it.consume()
},
onMove = { change ->
val position = change.positionChange()
val dragText = if (position.y < 0) {
"drag up"
} else if (position.y > 0) {
"drag down"
} else {
"idle"
}
text = "position: ${change.position}\n" +
"positionChange: ${change.positionChange()}\n" +
"dragText: $dragText"
}
)
)
}
}
}

Modifier.pointerMotionEvents() is a gesture Modifier i wrote, it's available here.