I want to detect a gesture in @Composable, which will allow me to drag an element across the screen in any direction.
I tried using LongPressDragObserver but after dragging for a bit, it snaps to a single Orientation (either Horizontally or Vertically) and Offset doesn't change for the other Orientation at all (it will equal to 0 all the time)
Example functionality I want to achieve:
Long press on the FAB and drag it around the screen so that it's position is constantly under user's finger.
I'm using Compose 1.0.0-alpha04
Example code which drags in only one direction (thanks to Rafsanjani)
.dragGestureFilter(dragObserver = object : DragObserver {
override fun onDrag(dragDistance: Offset): Offset {
val newX = dragDistance.x + verticalOffset.value
val newY = dragDistance.y + horizontalOffset.value
verticalOffset.value = newX
horizontalOffset.value = newY
return dragDistance
}
})
We can make the Column scrollable by using the verticalScroll() modifier.
A LazyColumn is a vertically scrolling list that only composes and lays out the currently visible items. It's similar to a Recyclerview in the classic Android View system.
There are two ways to declare the data within a ViewModel so that it is observable. One option is to use the Compose state mechanism which has been used extensively throughout this book. An alternative approach is to use the Jetpack LiveData component, a topic that will be covered later in this chapter.
mutableStateOf creates an observable MutableState<T> , which is an observable type integrated with the compose runtime. Any changes to value will schedule recomposition of any composable functions that read value . In the case of ExpandingCard , whenever expanded changes, it causes ExpandingCard to be recomposed.
You can use Modifier.pointerInput
with detectDragGestures
to do exactly the same as you want.
Example:
@Composable
fun Drag2DGestures() {
var size by remember { mutableStateOf(400.dp) }
val offsetX = remember { mutableStateOf(0f) }
val offsetY = remember { mutableStateOf(0f) }
Box(modifier = Modifier.size(size)){
Box(
Modifier
.offset { IntOffset(offsetX.value.roundToInt(), offsetY.value.roundToInt()) }
.background(Color.Blue)
.size(50.dp)
.pointerInput(Unit) {
detectDragGestures { change, dragAmount ->
change.consumeAllChanges()
offsetX.value = (offsetX.value + dragAmount.x)
.coerceIn(0f, size.width.toFloat() - 50.dp.toPx())
offsetY.value = (offsetY.value + dragAmount.y)
.coerceIn(0f, size.height.toFloat() - 50.dp.toPx())
}
}
)
Text("Drag the box around", Modifier.align(Alignment.Center))
}
}
will produce this result:
ٍٍٍSorry for the jank/drop in frames, the built-in emulator recorder cannot record 60fps smoothly
Compose version: alpha-11
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With