Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a drag gesture in any direction in Android Jetpack Compose

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 
  } 
})
like image 235
Mestru Avatar asked Oct 15 '20 20:10

Mestru


People also ask

How do I make my screen scrollable in jetpack compose?

We can make the Column scrollable by using the verticalScroll() modifier.

What is LazyColumn in jetpack compose?

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.

How do you get ViewModel in jetpack compose?

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.

What is mutableStateOf jetpack compose?

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.


1 Answers

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

enter image description here

Compose version: alpha-11

like image 114
MR3YY Avatar answered Oct 26 '22 19:10

MR3YY