diff options
2 files changed, 32 insertions, 9 deletions
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt index 974442494181..141736f46ee4 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt @@ -29,6 +29,7 @@ import com.android.compose.nestedscroll.PriorityNestedScrollConnection import com.android.compose.nestedscroll.ScrollController import com.android.compose.ui.util.SpaceVectorConverter import kotlin.math.absoluteValue +import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -359,13 +360,24 @@ private class DragControllerImpl( return swipeAnimation.animateOffset(velocity, targetContent) } - overscrollEffect.applyToFling( - velocity = velocity.toVelocity(), - performFling = { - val velocityLeft = it.toFloat() - swipeAnimation.animateOffset(velocityLeft, targetContent).toVelocity() - }, - ) + val overscrollCompletable = CompletableDeferred<Unit>() + try { + overscrollEffect.applyToFling( + velocity = velocity.toVelocity(), + performFling = { + val velocityLeft = it.toFloat() + swipeAnimation + .animateOffset( + velocityLeft, + targetContent, + overscrollCompletable = overscrollCompletable, + ) + .toVelocity() + }, + ) + } finally { + overscrollCompletable.complete(Unit) + } return velocity } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt index 5aaeda84edf0..47daa76b61d0 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt @@ -271,7 +271,7 @@ internal class SwipeAnimation<T : ContentKey>( /** The offset animation that animates the offset once the user lifts their finger. */ private var offsetAnimation: Animatable<Float, AnimationVector1D>? by mutableStateOf(null) - private val offsetAnimationRunnable = CompletableDeferred<(suspend () -> Unit)?>() + private val offsetAnimationRunnable = CompletableDeferred<suspend () -> Unit>() val isUserInputOngoing: Boolean get() = offsetAnimation == null @@ -333,6 +333,7 @@ internal class SwipeAnimation<T : ContentKey>( initialVelocity: Float, targetContent: T, spec: AnimationSpec<Float>? = null, + overscrollCompletable: CompletableDeferred<Unit>? = null, ): Float { check(!isAnimatingOffset()) { "SwipeAnimation.animateOffset() can only be called once" } @@ -391,7 +392,12 @@ internal class SwipeAnimation<T : ContentKey>( // detail). if (skipAnimation) { // Unblock the job. - offsetAnimationRunnable.complete(null) + offsetAnimationRunnable.complete { + // Wait for overscroll to finish so that the transition is removed from the STLState + // only after the overscroll is done, to avoid dropping frame right when the user + // lifts their finger and overscroll is animated to 0. + overscrollCompletable?.await() + } return 0f } @@ -450,6 +456,11 @@ internal class SwipeAnimation<T : ContentKey>( // The animation consumed the whole available velocity velocityConsumed.complete(initialVelocity) } + + // Wait for overscroll to finish so that the transition is removed from the STLState + // only after the overscroll is done, to avoid dropping frame right when the user + // lifts their finger and overscroll is animated to 0. + overscrollCompletable?.await() } } |