@@ -39,6 +39,7 @@ import androidx.compose.ui.draw.clip
3939import androidx.compose.ui.graphics.Color
4040import androidx.compose.ui.graphics.graphicsLayer
4141import androidx.compose.ui.input.pointer.pointerInput
42+ import androidx.compose.ui.input.pointer.util.VelocityTracker
4243import androidx.compose.ui.layout.onGloballyPositioned
4344import androidx.compose.ui.platform.LocalDensity
4445import androidx.compose.ui.text.font.FontWeight
@@ -54,6 +55,7 @@ import top.yukonga.miuix.kmp.utils.G2RoundedCornerShape
5455import top.yukonga.miuix.kmp.utils.MiuixPopupUtils.Companion.DialogLayout
5556import top.yukonga.miuix.kmp.utils.PredictiveBackHandler
5657import top.yukonga.miuix.kmp.utils.getWindowSize
58+ import kotlin.math.abs
5759
5860/* *
5961 * A bottom sheet that slides up from the bottom of the screen.
@@ -338,6 +340,7 @@ private fun DragHandleArea(
338340 val isPressing = remember { mutableFloatStateOf(0f ) }
339341 val pressScale = remember { Animatable (1f ) }
340342 val pressWidth = remember { Animatable (45f ) }
343+ val velocityTracker = remember { VelocityTracker () }
341344
342345 Box (
343346 modifier = Modifier
@@ -349,6 +352,7 @@ private fun DragHandleArea(
349352 coroutineScope.launch {
350353 dragStartOffset.floatValue = dragOffsetY.value
351354 dragOffsetY.snapTo(dragOffsetY.value)
355+ velocityTracker.resetTracking()
352356 // Animate press effect
353357 isPressing.floatValue = 1f
354358 launch {
@@ -384,18 +388,28 @@ private fun DragHandleArea(
384388
385389 val currentOffset = dragOffsetY.value
386390 val dragDelta = currentOffset - dragStartOffset.floatValue
391+ val velocity = velocityTracker.calculateVelocity().y
392+ val velocityThreshold = 500f
387393
388394 when {
389- // Dragged down significantly -> dismiss
390- dragDelta > 150f -> {
395+ // Dragged down far enough or has strong downward velocity -> dismiss
396+ (abs(velocity) > velocityThreshold || dragDelta.dp >= 200 .dp) && velocity <= 0 -> {
391397 onDismissRequest?.invoke()
392398 val windowHeightPx = windowHeight.value * density.density
393399 dragOffsetY.animateTo(
394400 targetValue = windowHeightPx,
395401 animationSpec = tween(durationMillis = 250 )
396402 )
397403 }
398- // Reset to original position (including overscroll bounce back)
404+ // Dragged up far enough or has strong upward velocity -> reset to original position
405+ abs(velocity) > velocityThreshold && velocity > 0 -> {
406+ dragOffsetY.animateTo(
407+ targetValue = 0f ,
408+ animationSpec = tween(durationMillis = 250 )
409+ )
410+ dimAlpha.value = 1f
411+ }
412+ // Not dragged far enough -> reset to original position
399413 else -> {
400414 dragOffsetY.animateTo(
401415 targetValue = 0f ,
@@ -406,8 +420,10 @@ private fun DragHandleArea(
406420 }
407421 }
408422 },
409- onVerticalDrag = { _ , dragAmount ->
423+ onVerticalDrag = { change , dragAmount ->
410424 coroutineScope.launch {
425+ velocityTracker.addPosition(change.uptimeMillis, change.position)
426+
411427 val newOffset = dragOffsetY.value + dragAmount
412428
413429 // Apply damping effect when dragging upward (negative offset)
0 commit comments