ドラッグ、スワイプ、フリング

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

指の押下によってドラッグされる UI 要素

スワイプ

swipeable 修飾子を使用すると、要素を離したときに、通常は 1 つの方向に定義された 2 つ以上のアンカー ポイントに向かって移動するアニメーションが表示されるような方法で、要素をドラッグできます。この修飾子は、「スワイプして閉じる」パターンを実装するためによく使用されます。

この修飾子は要素を移動せず、操作の検出のみを行う点に注意してください。たとえば、offset 修飾子を使用して要素を移動することにより、状態を保持して画面上で表現する必要があります。

スワイプ可能な状態は swipeable 修飾子で必須であり、rememberSwipeableState() で作成し、記憶することができます。この状態では、プログラムでアンカーへの移動のアニメーションを表示する便利なメソッドのセット(snapToanimateToperformFlingperformDrag を参照)と、ドラッグの進行状況を観測するためのプロパティも利用できます。

スワイプ操作は、FixedThreshold(Dp)FractionalThreshold(Float) のような各種のしきい値タイプを持つように構成できます。また、出発点と到着点のアンカー ポイントの組み合わせごとに、異なるスワイプ操作を構成することもできます。

柔軟性を高めるために、境界を超えてスワイプする際の resistance を構成できます。また、スワイプが位置の 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)
        )
    }
}

スワイプ操作に応答する UI 要素