Reorderable icon indicating copy to clipboard operation
Reorderable copied to clipboard

[FR]: longPressDraggable Support for onLongPress Event & onClick Event

Open azrael8576 opened this issue 1 year ago β€’ 4 comments

This library is amazing!

However, I have a requirement for longPressDraggable where I need to respond to onLongPress first before responding to onDragStarted().

Currently, the internal implementation of longPressDraggable intercepts the long press event. Could you add a new function or an interface like onLongPress: () -> Unit = { }?

azrael8576 avatar Oct 18 '24 09:10 azrael8576

Hmm can't you just use onDragStart? It should be called right after a long press

longPressDraggable uses detectDragGesturesAfterLongPress which doesn't have a separate onLongPress so I don't know how I can add one easily.

suspend fun PointerInputScope.detectDragGesturesAfterLongPress(
    onDragStart: (Offset) -> Unit = { },
    onDragEnd: () -> Unit = { },
    onDragCancel: () -> Unit = { },
    onDrag: (change: PointerInputChange, dragAmount: Offset) -> Unit
)

Or are you suggesting something like making onDragStarted a suspend function where dragging wouldn't start until it returns?

Calvin-LL avatar Oct 18 '24 19:10 Calvin-LL

Yes, this approach can solve the issue of missing the onLongPress event. However, my requirement also includes an onClick event, which I use to trigger navigation actions.

When I attempted to chain .clickable() with longPressDraggable() using Modifier, I found that the .clickable() event would be triggered after the drag ends, leading to unexpected navigation behavior.

To address this, I adjusted the code to use awaitPointerEventScope for gesture detection, and I submitted a PR to demonstrate this functionality: https://github.com/Calvin-LL/Reorderable/pull/56.

Would you be willing to allow me to continue contributing to this feature request?
Alternatively, would you consider changing the internal modifier in ReorderableLazyCollection.kt to open, so that users of the library can override it themselves?

azrael8576 avatar Oct 21 '24 07:10 azrael8576

First off, this library was a godsend. THANK YOU TO EVERYONE INVOLVED πŸ™.

I have a similar requirement for detecting clicks vs long presses vs dragged.

Situations I need to handle: βœ…The item is clickable, which works currently βœ…The item should be dragged on long press, this currently works by long pressing and then dragging 🟑The item should be selectable on long press.

This currently does not work because I don't have a hook to detect that the item was long pressed but not moved. For instance, if the item was long pressed but ended back up in the same location, then I can treat it as selected in my UI. The onMove routine doesn't fire if the item is over it's original square, so I can't use that (ie, from == to). The onDragStarted handler gives me startedPosition, but without final position on onDragStopped I can't determine where it ended up.

Is that possible to add startedPosition and finalPosition (or just finalPosition) on the onDragStopped handler please?

JeffWScott avatar Mar 05 '25 22:03 JeffWScott

You can handle events before they pass to longPressDraggable. However, you should not do a consume() as this will cause the drag event to be cancelled.

val touchSlop = LocalViewConfiguration.current.touchSlop
var isOverSlop by remember { mutableStateOf(false) }

Modifier
    .longPressDraggableHandle()
    .pointerInput(Unit) {
        awaitEachGesture {
            while (true) {
                val down = awaitFirstDown()
                val longPress = awaitLongPressOrCancellation(down.id) ?: return@awaitEachGesture

                drag(longPress.id) { change ->
                    if (isOverSlop) return@drag

                    val dragMovement = longPress.position - change.position

                    if (maxOf(abs(dragMovement.x), abs(dragMovement.y)) > touchSlop) {
                        isOverSlop = true
                    }
                }

                // After the drag event is over
                if (!isOverSlop) {
                    onLongPress()
                }

                isOverSlop = false
            }
        }
    }

rururux avatar Apr 02 '25 23:04 rururux

v2.5.0 has dragGestureDetector in Modifier.draggableHandle now. It should be possible to add custom gestures with it.

Calvin-LL avatar Jun 07 '25 06:06 Calvin-LL

Legend πŸ‘πŸ‘

Thanks a lot for real!

JeffWScott avatar Jun 07 '25 11:06 JeffWScott

Legend indeed πŸ™πŸ»

rufatagayev avatar Aug 20 '25 14:08 rufatagayev