Skip to content

Commit c729f1c

Browse files
committed
library: SuperBottomSheet: improve drag logic
1 parent 7d9ecbc commit c729f1c

File tree

2 files changed

+38
-28
lines changed

2 files changed

+38
-28
lines changed

iosApp/iosApp/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<key>CFBundleShortVersionString</key>
1818
<string>1.0.5</string>
1919
<key>CFBundleVersion</key>
20-
<string>568</string>
20+
<string>569</string>
2121
<key>LSRequiresIPhoneOS</key>
2222
<true/>
2323
<key>CADisableMinimumFrameDurationOnPhone</key>

miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/extra/SuperBottomSheet.kt

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import androidx.compose.ui.draw.clip
3939
import androidx.compose.ui.graphics.Color
4040
import androidx.compose.ui.graphics.graphicsLayer
4141
import androidx.compose.ui.input.pointer.pointerInput
42+
import androidx.compose.ui.input.pointer.util.VelocityTracker
4243
import androidx.compose.ui.layout.onGloballyPositioned
4344
import androidx.compose.ui.platform.LocalDensity
4445
import androidx.compose.ui.text.font.FontWeight
@@ -338,6 +339,7 @@ private fun DragHandleArea(
338339
val isPressing = remember { mutableFloatStateOf(0f) }
339340
val pressScale = remember { Animatable(1f) }
340341
val pressWidth = remember { Animatable(45f) }
342+
val velocityTracker = remember { VelocityTracker() }
341343

342344
Box(
343345
modifier = Modifier
@@ -349,6 +351,7 @@ private fun DragHandleArea(
349351
coroutineScope.launch {
350352
dragStartOffset.floatValue = dragOffsetY.value
351353
dragOffsetY.snapTo(dragOffsetY.value)
354+
velocityTracker.resetTracking()
352355
// Animate press effect
353356
isPressing.floatValue = 1f
354357
launch {
@@ -384,18 +387,29 @@ private fun DragHandleArea(
384387

385388
val currentOffset = dragOffsetY.value
386389
val dragDelta = currentOffset - dragStartOffset.floatValue
390+
val velocity = velocityTracker.calculateVelocity().y
391+
val velocityThreshold = 500f
392+
val dismissThresholdPx = with(density) { 150.dp.toPx() }
387393

388394
when {
389-
// Dragged down significantly -> dismiss
390-
dragDelta > 150f -> {
395+
// Dragged far enough down or has strong downward velocity -> dismiss
396+
dragDelta >= dismissThresholdPx || (velocity < -velocityThreshold && dragDelta > 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+
// Has strong upward velocity -> continue to expand
405+
velocity > velocityThreshold -> {
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,34 +420,30 @@ private fun DragHandleArea(
406420
}
407421
}
408422
},
409-
onVerticalDrag = { _, dragAmount ->
410-
coroutineScope.launch {
411-
val newOffset = dragOffsetY.value + dragAmount
412-
413-
// Apply damping effect when dragging upward (negative offset)
414-
val finalOffset = if (newOffset < 0) {
415-
// Overscroll effect: reduce drag amount with damping
416-
val dampingFactor = 0.1f // Adjust this value for more/less resistance
417-
val dampedAmount = dragAmount * dampingFactor
418-
(dragOffsetY.value + dampedAmount).coerceAtMost(0f)
419-
} else {
420-
// Normal drag downward
421-
newOffset
422-
}
423+
onVerticalDrag = { change, dragAmount ->
424+
velocityTracker.addPosition(change.uptimeMillis, change.position)
425+
426+
val newOffset = dragOffsetY.value + dragAmount
427+
428+
val finalOffset = if (newOffset < 0) {
429+
val dampingFactor = 0.1f
430+
val dampedAmount = dragAmount * dampingFactor
431+
(dragOffsetY.value + dampedAmount).coerceAtMost(0f)
432+
} else {
433+
newOffset
434+
}
423435

436+
coroutineScope.launch {
424437
dragOffsetY.snapTo(finalOffset)
438+
}
425439

426-
// Update dim alpha based on downward drag only
427-
val thresholdPx = if (sheetHeightPx.value > 0) sheetHeightPx.value.toFloat() else 500f
428-
val alpha = if (finalOffset >= 0) {
429-
// Dragging down - reduce alpha
430-
1f - (finalOffset / thresholdPx).coerceIn(0f, 1f)
431-
} else {
432-
// Dragging up or at base position - keep alpha at 1
433-
1f
434-
}
435-
dimAlpha.value = alpha
440+
val thresholdPx = if (sheetHeightPx.value > 0) sheetHeightPx.value.toFloat() else 500f
441+
val alpha = if (finalOffset >= 0) {
442+
1f - (finalOffset / thresholdPx).coerceIn(0f, 1f)
443+
} else {
444+
1f
436445
}
446+
dimAlpha.value = alpha
437447
}
438448
)
439449
},

0 commit comments

Comments
 (0)