Trascina, scorri e scorri

Il modificatore draggable è il punto di contatto di alto livello per i gesti di trascinamento in un singolo orientamento e indica la distanza di trascinamento in pixel.

È importante notare che questo modificatore è simile a scrollable, in quanto rileva solo il gesto. Devi mantenere lo stato e rappresentarlo sullo schermo, ad esempio spostando l'elemento tramite il modificatore 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!"
    )
}

Se devi controllare l'intero gesto di trascinamento, valuta la possibilità di utilizzare il rilevatore di gesti di trascinamento tramite il modificatore 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
                    }
                }
        )
    }
}

Un elemento dell'interfaccia utente trascinato premendo un dito

Scorrimento

Il modificatore swipeable ti consente di trascinare gli elementi che, quando vengono rilasciati, si animano in genere verso due o più punti di ancoraggio definiti in un orientamento. Un utilizzo comune è implementare un pattern di scorrimento per chiudere.

È importante notare che questo modificatore non sposta l'elemento, ma solo rileva il gesto. Devi mantenere lo stato e rappresentarlo sullo schermo, ad esempio spostando l'elemento tramite il modificatore offset.

Lo stato scorrevole è obbligatorio nel modificatore swipeable e può essere creato e memorizzato con rememberSwipeableState(). Questo stato fornisce anche un insieme di metodi utili per animare in modo programmatico gli elementi in base agli ancoraggi (vedi snapTo, animateTo, performFling e performDrag) nonché proprietà per osservare l'avanzamento del trascinamento.

Il gesto di scorrimento può essere configurato per avere diversi tipi di soglie, ad esempio FixedThreshold(Dp) e FractionalThreshold(Float), e possono essere diversi per ogni combinazione da-a del punto di ancoraggio.

Per una maggiore flessibilità, puoi configurare resistance quando scorri oltre i limiti e anche velocityThreshold che animerà uno scorrimento allo stato successivo, anche se i thresholds posizionali non sono stati raggiunti.

@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)
        )
    }
}

Un elemento dell'interfaccia utente che risponde a un gesto di scorrimento