Arrastar, deslizar e deslizar
Mantenha tudo organizado com as coleções
Salve e categorize o conteúdo com base nas suas preferências.
O modificador
draggable
é o ponto de entrada de alto nível para gestos de arrastar em uma única orientação
e informa a distância da ação de arrastar em pixels.
É importante observar que esse modificador é semelhante a scrollable
, porque
ele detecta apenas o gesto. É necessário manter o estado e representá-lo na tela,
por exemplo, movendo o elemento com o
modificador
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!"
)
}
Caso você precise controlar todo o gesto de arrastar, considere usar o detector de gestos
de arrastar, com o
modificador
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
}
}
)
}
}
Deslizar
O modificador
swipeable
permite arrastar elementos que, quando soltos, são animados em direção a dois ou
mais pontos de fixação definidos na orientação. Um uso comum para isso é
a implementação do padrão "deslizar para dispensar".
Esse modificador não move o elemento,
apenas detecta o gesto. É necessário manter o estado e representá-lo na tela,
por exemplo, movendo o elemento com o
modificador
offset
.
O estado deslizante é obrigatório no modificador swipeable
e pode ser criado
e lembrado com
rememberSwipeableState()
.
Esse estado também fornece um conjunto de métodos úteis para inserir animações de forma programática
nos pontos fixos (consulte
snapTo
,
animateTo
,
performFling
e
performDrag
)
e as propriedades para observar o progresso da ação de arrastar.
O gesto de deslizar pode ser configurado para ter diferentes tipos de limite, como
FixedThreshold(Dp)
e
FractionalThreshold(Float)
.
Esses limites podem ser diferentes para cada combinação de ponto de partida e chegada dos pontos fixos.
Para ter mais flexibilidade, você pode configurar resistance
ao deslizar para além dos
limites. Também é possível configurar velocityThreshold
, que fará a animação do gesto de deslizar para o
próximo estado, mesmo que os thresholds
não tenham sido alcançados.
@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)
)
}
}
Recomendados para você
O conteúdo e os exemplos de código nesta página estão sujeitos às licenças descritas na Licença de conteúdo. Java e OpenJDK são marcas registradas da Oracle e/ou suas afiliadas.
Última atualização 2025-08-25 UTC.
[[["Fácil de entender","easyToUnderstand","thumb-up"],["Meu problema foi resolvido","solvedMyProblem","thumb-up"],["Outro","otherUp","thumb-up"]],[["Não contém as informações de que eu preciso","missingTheInformationINeed","thumb-down"],["Muito complicado / etapas demais","tooComplicatedTooManySteps","thumb-down"],["Desatualizado","outOfDate","thumb-down"],["Problema na tradução","translationIssue","thumb-down"],["Problema com as amostras / o código","samplesCodeIssue","thumb-down"],["Outro","otherDown","thumb-down"]],["Última atualização 2025-08-25 UTC."],[],[],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)"]]