Перетаскивание с помощью PointerInputScope

Последнее обновление: 19.04.2024

В прошлой теме был рассмотрен модификатор draggable(), который позволяет нам реализовать перетаскивание компонента. Однако этот модификатор имеет ограничение: одновременно он может использовать либо перетаскивание по горизонтали, либо по вертикали. Функция detectDragGestures() типа PointerInputScope решает эту проблему и позволяет нам одновременно поддерживать операции горизонтального и вертикального перетаскивания. Эта функция имеет следующие параметры:

suspend fun PointerInputScope.detectDragGestures(
    onDragStart: (Offset) -> Unit = { },
    onDragEnd: () -> Unit = { },
    onDragCancel: () -> Unit = { },
    onDrag: (change: PointerInputChange, dragAmount: Offset) -> Unit
): Unit
  • onDragStart: функция, которая вызывается при начале перетаскивания

  • onDragEnd: функция, которая вызывается после завершения перетаскивания

  • onDragCancel: функция, которая вызывается при отмене перетаскивания

  • onDrag: функция, которая вызывается при перетаскивания

Нам достаточно задать последний параметр для управления перетаскиваемым компонентом. И обработка перетаскивания в общем случае будет выглядеть примерно следующим образом:

Modifier.pointerInput(Unit) {
    detectDragGestures { _, distance ->
        xOffset += distance.x
        yOffset += distance.y
    }
}

Рассмотрим небольшой пример:

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.gestures.draggable
import androidx.compose.foundation.gestures.rememberDraggableState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Text

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlin.math.roundToInt


class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            var xOffset by remember { mutableStateOf(0f) }
            var yOffset by remember { mutableStateOf(0f) }
            
            Column(Modifier.fillMaxSize()) {
                Text("xOffset: $xOffset ; yOffset: $yOffset", Modifier.padding(10.dp), fontSize=22.sp)
                Box(
                    Modifier
                        .offset { IntOffset(xOffset.roundToInt(), yOffset.roundToInt()) }
                        .background(Color.DarkGray)
                        .size(150.dp)
                        .pointerInput(Unit) {
                            detectDragGestures { _, distance ->
                                xOffset += distance.x
                                yOffset += distance.y
                            }
                        }
                )
            }
        }
    }
}

Для отслеживания перетаскивания как по горизонтали, так и по вертикали, определяются две переменных состояния для хранения смещений по оси X и Y:

var xOffset by remember { mutableStateOf(0f) }
var yOffset by remember { mutableStateOf(0f) }

К их значениям привязаны координаты компонента Box:

Box(
    Modifier.offset { IntOffset(xOffset.roundToInt(), yOffset.roundToInt()) }

В лямбда-выражение в функции detectDragGestures передается параметр distance, который представляет объект Offset и из которого мы можем получить последние значения смещения перетаскивания по осям x и y. Они добавляются к состояниям xOffset и yOffset соответственно, в результате чего компонент Box следует за движением перетаскивания по экрану:

.pointerInput(Unit) {
    detectDragGestures { _, distance ->
        xOffset += distance.x
        yOffset += distance.y
    }
}

И для наглядности координаты перемещения выводятся на экран ыв компоненте Text:

Обработка перетаскивания и модификатор pointerInput в Jetpack Compose Kotlin Android
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850