拖动、滑动和快速滑动
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
draggable
修饰符是向单一方向拖动手势的高级入口点,并且会报告拖动距离(以像素为单位)。
请务必注意,此修饰符与 scrollable
类似,仅检测手势。您需要保存状态并在屏幕上表示,例如通过 offset
修饰符移动元素:
@Composable
private fun DraggableText() {
var offsetX by remember { mutableStateOf(0f) }
Text(
modifier = Modifier
.offset { IntOffset(offsetX.roundToInt(), 0) }
.draggable(
orientation = Orientation.Horizontal,
state = rememberDraggableState { delta ->
offsetX += delta
}
),
text = "Drag me!"
)
}
如果您需要控制整个拖动手势,请考虑改为通过 pointerInput
修饰符使用拖动手势检测器。
@Composable
private fun DraggableTextLowLevel() {
Box(modifier = Modifier.fillMaxSize()) {
var offsetX by remember { mutableStateOf(0f) }
var offsetY by remember { mutableStateOf(0f) }
Box(
Modifier
.offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
.background(Color.Blue)
.size(50.dp)
.pointerInput(Unit) {
detectDragGestures { change, dragAmount ->
change.consume()
offsetX += dragAmount.x
offsetY += dragAmount.y
}
}
)
}
}
滑动
您可以使用 swipeable
修饰符拖动元素,释放后,这些元素通常朝一个方向定义的两个或多个锚点呈现动画效果。其常见用途是实现“滑动关闭”模式。
请务必注意,此修饰符不会移动元素,而只检测手势。您需要保存状态并在屏幕上表示,例如通过 offset
修饰符移动元素。
在 swipeable
修饰符中必须提供可滑动状态,且该状态可以通过 rememberSwipeableState()
创建和记住。此状态还提供了一组有用的方法,用于以程序化方式为锚点添加动画效果(请参阅 snapTo
、animateTo
、performFling
和 performDrag
),同时为属性添加动画效果,以观察拖动进度。
可以将滑动手势配置为具有不同的阈值类型,例如 FixedThreshold(Dp)
和 FractionalThreshold(Float)
,并且对于每个锚点的起始与终止组合,它们可以是不同的。
为了获得更大的灵活性,您可以配置滑动越过边界时的 resistance
,还可以配置 velocityThreshold
,即使尚未达到位置 thresholds
,velocityThreshold 仍将以动画方式向下一个状态滑动。
@OptIn(ExperimentalMaterialApi::class)
@Composable
private fun SwipeableSample() {
val width = 96.dp
val squareSize = 48.dp
val swipeableState = rememberSwipeableState(0)
val sizePx = with(LocalDensity.current) { squareSize.toPx() }
val anchors = mapOf(0f to 0, sizePx to 1) // Maps anchor points (in px) to states
Box(
modifier = Modifier
.width(width)
.swipeable(
state = swipeableState,
anchors = anchors,
thresholds = { _, _ -> FractionalThreshold(0.3f) },
orientation = Orientation.Horizontal
)
.background(Color.LightGray)
) {
Box(
Modifier
.offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }
.size(squareSize)
.background(Color.DarkGray)
)
}
}
为您推荐
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-08-25。
[null,null,["最后更新时间 (UTC):2025-08-25。"],[],[],null,["# Drag, swipe, and fling\n\nThe\n[`draggable`](/reference/kotlin/androidx/compose/foundation/gestures/package-summary#(androidx.compose.ui.Modifier).draggable(androidx.compose.foundation.gestures.DraggableState,androidx.compose.foundation.gestures.Orientation,kotlin.Boolean,androidx.compose.foundation.interaction.MutableInteractionSource,kotlin.Boolean,kotlin.coroutines.SuspendFunction2,kotlin.coroutines.SuspendFunction2,kotlin.Boolean))\nmodifier is the high-level entry point to drag gestures in a single orientation,\nand reports the drag distance in pixels.\n\nIt's important to note that this modifier is similar to `scrollable`, in that it\nonly detects the gesture. You need to hold the state and represent it on screen\nby, for example, moving the element via the\n[`offset`](/reference/kotlin/androidx/compose/foundation/layout/package-summary#(androidx.compose.ui.Modifier).offset(androidx.compose.ui.unit.Dp,%20androidx.compose.ui.unit.Dp))\nmodifier:\n\n\n```kotlin\n@Composable\nprivate fun DraggableText() {\n var offsetX by remember { mutableStateOf(0f) }\n Text(\n modifier = Modifier\n .offset { IntOffset(offsetX.roundToInt(), 0) }\n .draggable(\n orientation = Orientation.Horizontal,\n state = rememberDraggableState { delta -\u003e\n offsetX += delta\n }\n ),\n text = \"Drag me!\"\n )\n}https://github.com/android/snippets/blob/dd30aee903e8c247786c064faab1a9ca8d10b46e/compose/snippets/src/main/java/com/example/compose/snippets/touchinput/gestures/GesturesSnippets.kt#L250-L264\n```\n\n\u003cbr /\u003e\n\nIf you need to control the whole dragging gesture, consider using the drag\ngesture detector instead, via the\n[`pointerInput`](/reference/kotlin/androidx/compose/ui/input/pointer/package-summary#(androidx.compose.ui.Modifier).pointerInput(kotlin.Any,kotlin.coroutines.SuspendFunction1))\nmodifier.\n\n\n```kotlin\n@Composable\nprivate fun DraggableTextLowLevel() {\n Box(modifier = Modifier.fillMaxSize()) {\n var offsetX by remember { mutableStateOf(0f) }\n var offsetY by remember { mutableStateOf(0f) }\n\n Box(\n Modifier\n .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }\n .background(Color.Blue)\n .size(50.dp)\n .pointerInput(Unit) {\n detectDragGestures { change, dragAmount -\u003e\n change.consume()\n offsetX += dragAmount.x\n offsetY += dragAmount.y\n }\n }\n )\n }\n}https://github.com/android/snippets/blob/dd30aee903e8c247786c064faab1a9ca8d10b46e/compose/snippets/src/main/java/com/example/compose/snippets/touchinput/gestures/GesturesSnippets.kt#L268-L288\n```\n\n\u003cbr /\u003e\n\nSwiping\n-------\n\nThe\n[`swipeable`](/reference/kotlin/androidx/compose/material/package-summary#(androidx.compose.ui.Modifier).swipeable(androidx.compose.material.SwipeableState,kotlin.collections.Map,androidx.compose.foundation.gestures.Orientation,kotlin.Boolean,kotlin.Boolean,androidx.compose.foundation.interaction.MutableInteractionSource,kotlin.Function2,androidx.compose.material.ResistanceConfig,androidx.compose.ui.unit.Dp))\nmodifier lets you drag elements which, when released, animate towards typically\ntwo or more anchor points defined in an orientation. A common usage for this is\nto implement a 'swipe-to-dismiss' pattern.\n| **Caution:** The [`swipeable`](/reference/kotlin/androidx/compose/material/package-summary#(androidx.compose.ui.Modifier).swipeable(androidx.compose.material.SwipeableState,kotlin.collections.Map,androidx.compose.foundation.gestures.Orientation,kotlin.Boolean,kotlin.Boolean,androidx.compose.foundation.interaction.MutableInteractionSource,kotlin.Function2,androidx.compose.material.ResistanceConfig,androidx.compose.ui.unit.Dp)) APIs have been replaced by Foundation's [`anchoredDraggable`](/reference/kotlin/androidx/compose/foundation/gestures/package-summary#(androidx.compose.ui.Modifier).anchoredDraggable(androidx.compose.foundation.gestures.AnchoredDraggableState,androidx.compose.foundation.gestures.Orientation,kotlin.Boolean,kotlin.Boolean,androidx.compose.foundation.interaction.MutableInteractionSource)) APIs in Jetpack Compose 1.6.0-alpha01.\n\nIt's important to note that this modifier does not move the element, it only\ndetects the gesture. You need to hold the state and represent it on screen by,\nfor example, moving the element via the\n[`offset`](/reference/kotlin/androidx/compose/foundation/layout/package-summary#(androidx.compose.ui.Modifier).offset(androidx.compose.ui.unit.Dp,androidx.compose.ui.unit.Dp))\nmodifier.\n\nThe swipeable state is required in the `swipeable` modifier, and can be created\nand remembered with\n[`rememberSwipeableState()`](/reference/kotlin/androidx/compose/material/package-summary#rememberSwipeableState(kotlin.Any,androidx.compose.animation.core.AnimationSpec,kotlin.Function1)).\nThis state also provides a set of useful methods to programmatically animate to\nanchors (see\n[`snapTo`](/reference/kotlin/androidx/compose/material/SwipeableState#snapTo(kotlin.Any)),\n[`animateTo`](/reference/kotlin/androidx/compose/material/SwipeableState#animateTo(kotlin.Any,androidx.compose.animation.core.AnimationSpec)),\n[`performFling`](/reference/kotlin/androidx/compose/material/SwipeableState#performFling(kotlin.Float)),\nand\n[`performDrag`](/reference/kotlin/androidx/compose/material/SwipeableState#performDrag(kotlin.Float)))\nas well as properties to observe the dragging progress.\n\nThe swipe gesture can be configured to have different threshold types, such as\n[`FixedThreshold(Dp)`](/reference/kotlin/androidx/compose/material/FixedThreshold#FixedThreshold(androidx.compose.ui.unit.Dp))\nand\n[`FractionalThreshold(Float)`](/reference/kotlin/androidx/compose/material/FractionalThreshold#FractionalThreshold(kotlin.Float)),\nand they can be different for each anchor point from-to combination.\n\nFor more flexibility, you can configure the `resistance` when swiping past the\nbounds and, also, the `velocityThreshold` which will animate a swipe to the\nnext state, even if the positional `thresholds`have not been reached.\n\n\n```kotlin\n@OptIn(ExperimentalMaterialApi::class)\n@Composable\nprivate fun SwipeableSample() {\n val width = 96.dp\n val squareSize = 48.dp\n\n val swipeableState = rememberSwipeableState(0)\n val sizePx = with(LocalDensity.current) { squareSize.toPx() }\n val anchors = mapOf(0f to 0, sizePx to 1) // Maps anchor points (in px) to states\n\n Box(\n modifier = Modifier\n .width(width)\n .swipeable(\n state = swipeableState,\n anchors = anchors,\n thresholds = { _, _ -\u003e FractionalThreshold(0.3f) },\n orientation = Orientation.Horizontal\n )\n .background(Color.LightGray)\n ) {\n Box(\n Modifier\n .offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }\n .size(squareSize)\n .background(Color.DarkGray)\n )\n }\n}https://github.com/android/snippets/blob/dd30aee903e8c247786c064faab1a9ca8d10b46e/compose/snippets/src/main/java/com/example/compose/snippets/touchinput/gestures/GesturesSnippets.kt#L292-L320\n```\n\n\u003cbr /\u003e\n\nRecommended for you\n-------------------\n\n- Note: link text is displayed when JavaScript is off\n- [Understand gestures](/develop/ui/compose/touch-input/pointer-input/understand-gestures)\n- [Advanced animation example: Gestures {:#gesture-and-animation}](/develop/ui/compose/animation/advanced)\n- [Value-based animations](/develop/ui/compose/animation/value-based)"]]