Kéo, vuốt và hất

Phương thức sửa đổi draggable là điểm truy cập cấp cao cho các cử chỉ kéo theo một hướng đồng thời báo cáo khoảng cách kéo bằng pixel.

Quan trọng là bạn phải lưu ý rằng phương thức sửa đổi này tương tự như scrollable, vì phương thức này chỉ phát hiện cử chỉ. Bạn cần giữ và biểu thị trạng thái trên màn hình bằng cách di chuyển phần tử qua đối tượng sửa đổi 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!"
    )
}

Nếu bạn cần điều khiển toàn bộ cử chỉ kéo, hãy cân nhắc chuyển sang sử dụng trình phát hiện cử chỉ kéo, thông qua phương thức sửa đổi 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
                    }
                }
        )
    }
}

Một thành phần trên giao diện người dùng bị kéo bằng thao tác nhấn ngón tay

Vuốt

Phương thức sửa đổi swipeable cho phép bạn kéo các thành phần mà khi nhả ra sẽ tạo hiệu ứng động về phía hai hoặc nhiều điểm neo được xác định theo một hướng. Có một cách sử dụng phổ biến là triển khai mẫu hình "vuốt để đóng".

Quan trọng là bạn phải lưu ý rằng phương thức sửa đổi này không di chuyển phần tử, mà chỉ phát hiện thao tác. Bạn cần giữ và biểu thị trạng thái trên màn hình bằng cách di chuyển phần tử qua đối tượng sửa đổi offset:

Trạng thái có thể vuốt là bắt buộc trong phương thức sửa đổi swipeable. Bạn có thể tạo và ghi nhớ trạng thái này bằng rememberSwipeableState(). Trạng thái này cũng cung cấp một tập hợp phương thức hữu ích để lập trình hiệu ứng động đến các điểm neo (xem snapTo, animateTo, performFlingperformDrag) cũng như các thuộc tính để quan sát tiến trình kéo.

Bạn có thể định cấu hình cử chỉ vuốt để áp dụng nhiều loại ngưỡng như FixedThreshold(Dp)FractionalThreshold(Float) (những loại ngưỡng này có thể thay đổi tuỳ theo từng tổ hợp điểm neo từ-đến).

Để linh hoạt hơn, bạn có thể định cấu hình resistance khi vuốt qua ra ngoài phạm vi. Đồng thời, velocityThreshold sẽ tạo hiệu ứng vuốt sang trạng thái tiếp theo, ngay cả khi chưa đến vị trí thresholds.

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

Một thành phần trên giao diện người dùng phản hồi cử chỉ vuốt