Improve pager gesture handling (again)

This commit is contained in:
MM20 2023-07-12 17:41:04 +02:00
parent d1218e8d2e
commit 3759a99510
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389

View File

@ -667,37 +667,34 @@ fun Modifier.pagerScaffoldScrollHandler(
awaitEachGesture { awaitEachGesture {
var overSlop = false var overSlop = false
var lockedInScroll = disablePager val initialDown =
val initialDown = awaitFirstDown(requireUnconsumed = false, pass = PointerEventPass.Initial) awaitFirstDown(requireUnconsumed = false, pass = PointerEventPass.Initial)
val down = if (scrollableState.isScrollInProgress || pagerState.isScrollInProgress) { val down =
overSlop = true if (scrollableState.isScrollInProgress || pagerState.isScrollInProgress) {
scope.launch { overSlop = true
scrollableState.scrollBy(0f) scope.launch {
pagerState.scrollBy(0f) scrollableState.scrollBy(0f)
pagerState.scrollBy(0f)
}
initialDown
} else {
awaitFirstDown(requireUnconsumed = false)
} }
initialDown
} else {
awaitFirstDown(requireUnconsumed = false)
}
velocityTracker.resetTracking() velocityTracker.resetTracking()
velocityTracker.addPointerInputChange(down) velocityTracker.addPointerInputChange(down)
val notCanceled = drag(down.id) { val canceled = !drag(down.id) {
if (it.isConsumed) return@drag if (it.isConsumed) return@drag
val totalDrag = down.position - it.position val totalDrag = down.position - it.position
if (!lockedInScroll && totalDrag.y.absoluteValue > lockScrollThreshold) { if (!overSlop && totalDrag.getDistanceSquared() > touchSlopSq) {
lockedInScroll = true
scope.launch {
pagerState.animateScrollToPage(pagerState.settledPage)
}
}
if (!lockedInScroll && !overSlop && totalDrag.getDistanceSquared() > touchSlopSq) {
overSlop = true overSlop = true
} }
if (!overSlop) return@drag if (!overSlop) return@drag
val dragAmount = it val dragAmount = it
.positionChange() .positionChange()
.let { .let {
if (!overSlop || lockedInScroll) it.copy(x = 0f) else it if (it.x.absoluteValue > it.y.absoluteValue) it.copy(y = 0f) else it.copy(
x = 0f
)
} }
it.consume() it.consume()
velocityTracker.addPointerInputChange(it) velocityTracker.addPointerInputChange(it)
@ -707,11 +704,11 @@ fun Modifier.pagerScaffoldScrollHandler(
NestedScrollSource.Drag NestedScrollSource.Drag
) )
val available = dragAmount - preConsumed val available = dragAmount - preConsumed
val consumedY = scrollableState.scrollBy(available.y * scrollMultiplier) * scrollMultiplier val consumedY =
val consumedX = if (!lockedInScroll) { scrollableState.scrollBy(available.y * scrollMultiplier) * scrollMultiplier
pagerState.scrollBy(available.x * pagerMultiplier) * pagerMultiplier val consumedX = pagerState.scrollBy(available.x * pagerMultiplier) * -1f
} else available.x val totalConsumed =
val totalConsumed = Offset(preConsumed.x + consumedX, preConsumed.y + consumedY) Offset(preConsumed.x + consumedX, preConsumed.y + consumedY)
nestedScrollDispatcher.dispatchPostScroll( nestedScrollDispatcher.dispatchPostScroll(
totalConsumed, totalConsumed,
dragAmount - totalConsumed, dragAmount - totalConsumed,
@ -719,51 +716,50 @@ fun Modifier.pagerScaffoldScrollHandler(
) )
} }
} }
if (notCanceled) { val velocity = velocityTracker
val velocity = velocityTracker .calculateVelocity()
.calculateVelocity()
if (velocity.x.absoluteValue > velocity.y.absoluteValue && !lockedInScroll) { if (canceled || velocity.x.absoluteValue > velocity.y.absoluteValue) {
scope.launch { scope.launch {
val preConsumed = nestedScrollDispatcher.dispatchPreFling(velocity) val preConsumed = nestedScrollDispatcher.dispatchPreFling(velocity)
val flingVelocity = (velocity - preConsumed).x val flingVelocity = (velocity - preConsumed).x
if (flingVelocity.absoluteValue > 400.dp.toPx()) { if (flingVelocity.absoluteValue > 400.dp.toPx()) {
if (flingVelocity * pagerMultiplier < 0) { if (flingVelocity * pagerMultiplier < 0) {
pagerState.animateScrollToPage(pagerState.settledPage - 1) pagerState.animateScrollToPage(pagerState.settledPage - 1)
} else {
pagerState.animateScrollToPage(pagerState.settledPage + 1)
}
} else { } else {
pagerState.animateScrollToPage(pagerState.settledPage) pagerState.animateScrollToPage(pagerState.settledPage + 1)
} }
} else {
pagerState.animateScrollToPage(pagerState.settledPage)
}
nestedScrollDispatcher.dispatchPostFling(
velocity,
Velocity.Zero,
)
}
} else {
scope.launch {
val preConsumed = nestedScrollDispatcher.dispatchPreFling(velocity)
val flingVelocity = (velocity - preConsumed).y
var consumed = 0f
launch {
with(flingBehavior) {
scrollableState.scroll {
consumed =
performFling(flingVelocity * scrollMultiplier) * scrollMultiplier
}
}
val totalConsumed =
Velocity(preConsumed.x, preConsumed.y + consumed)
nestedScrollDispatcher.dispatchPostFling( nestedScrollDispatcher.dispatchPostFling(
velocity, totalConsumed,
Velocity.Zero, velocity - totalConsumed
) )
} }
} else { launch {
scope.launch { pagerState.animateScrollToPage(pagerState.settledPage)
val preConsumed = nestedScrollDispatcher.dispatchPreFling(velocity)
val flingVelocity = (velocity - preConsumed).y
var consumed = 0f
launch {
with(flingBehavior) {
scrollableState.scroll {
consumed = performFling(flingVelocity * scrollMultiplier) * scrollMultiplier
}
}
val totalConsumed =
Velocity(preConsumed.x, preConsumed.y + consumed)
nestedScrollDispatcher.dispatchPostFling(
totalConsumed,
velocity - totalConsumed
)
}
launch {
pagerState.animateScrollToPage(pagerState.settledPage)
}
} }
} }
} }