В прошлой теме был рассмотрен модификатор 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: