Skip to content

Commit

Permalink
Fix unexpected fling behaviors.
Browse files Browse the repository at this point in the history
- Use a position relative to the root component to calculate velocity.
- Reset VelocityTracker when drag gesture starts.
- Cancel fling animation when another drag gesture starts.
- Don't do scroll process when the position does not change.
  • Loading branch information
usuiat committed Sep 26, 2023
1 parent 98e0c88 commit 3f69c52
Showing 1 changed file with 21 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.input.pointer.positionChange
import androidx.compose.ui.input.pointer.util.VelocityTracker
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.semantics.ScrollAxisRange
Expand Down Expand Up @@ -228,8 +230,14 @@ fun TimetableGrid(
}
},
)
.onGloballyPositioned { coordinates ->
timetableState.screenScrollState.componentPositionInRoot = coordinates.positionInRoot()
}
.pointerInput(Unit) {
detectDragGestures(
onDragStart = {
scrollState.resetTracking()
},
onDrag = { change, dragAmount ->
if (timetableScreen.enableHorizontalScroll(dragAmount.x)) {
if (change.positionChange() != Offset.Zero) change.consume()
Expand Down Expand Up @@ -482,6 +490,8 @@ class ScreenScrollState(
private val velocityTracker = VelocityTracker()
private val _scrollX = Animatable(initialScrollX)
private val _scrollY = Animatable(initialScrollY)
var componentPositionInRoot = Offset.Zero
private var cancelFling = false

val scrollX: Float
get() = _scrollX.value
Expand All @@ -499,9 +509,11 @@ class ScreenScrollState(
timeMillis: Long,
position: Offset,
) {
cancelFling = true
if (scrollX.isNaN().not() && scrollY.isNaN().not()) {
coroutineScope {
velocityTracker.addPosition(timeMillis = timeMillis, position = position)
val positionInRoot = position + componentPositionInRoot
velocityTracker.addPosition(timeMillis = timeMillis, position = positionInRoot)
launch {
_scrollX.snapTo(scrollX)
}
Expand All @@ -513,6 +525,7 @@ class ScreenScrollState(
}

suspend fun flingIfPossible(nestedScrollDispatcher: NestedScrollDispatcher) = coroutineScope {
cancelFling = false
val velocity = velocityTracker.calculateVelocity()
launch {
_scrollX.animateDecay(
Expand Down Expand Up @@ -546,6 +559,10 @@ class ScreenScrollState(
available = weAvailable - weConsumed,
source = NestedScrollSource.Fling,
)

if (cancelFling) {
this@animateDecay.cancelAnimation()
}
}
}
}
Expand Down Expand Up @@ -696,6 +713,9 @@ private class TimetableScreen(
position: Offset,
nestedScrollDispatcher: NestedScrollDispatcher,
) {
// If the position does not change, VelocityTracker malfunctions. Therefore return here.
if (dragAmount == Offset.Zero) return

val parentConsumed = nestedScrollDispatcher.dispatchPreScroll(
available = dragAmount,
source = NestedScrollSource.Drag,
Expand Down

0 comments on commit 3f69c52

Please sign in to comment.