Dropper

An easy Drop And Drag Api provider for Jetpack Compose.

Usage

Implementation

Add it in your root build.gradle at the end of repositories:

allprojects {
		repositories {
			...
			maven { url 'https://jitpack.io' }
		}
	}

Add the dependency

dependencies {
	        implementation 'com.github.fogsong233:Dropper:v1.0.0'
	}

first, create a new Dropper instance, and you can create DroppableRef and DraggableRef

// <String> is which type of addition info the draggable provides to droppable with
val dropper by remember { mutableStateOf(Dropper<String>()) }

Now you can create refs. Info is the addition type, Dropper can automatically check the position of draggable and invoke the callback.

val dropRef = dropper.createDroppableRef(DroppableEventCallBack(
                onEnter = { name, info ->
                    Log.d(tag, "enter: $name, info: $info")
                },
                onDrop = { name, info ->
                    Log.d(tag, "drop: $name, info: $info")
                },
                onLeave = { name ->
                    Log.d(tag, "leave: $name")
                }
            ))

then create draggable:

val dragRef = dropper.createDraggableRef("name", "info: T", DraggableEventCallBack(
    // where you can listen drop, drag, dragStart, dragCancelled events.
    onDrop = {}
    ...
))

Now bind them to component:

Box(modifier = Modifier.draggable(dragRef, afterLongPress = true/false))
Box( modifier = Modifier.droppable(dropRef))

Custom Offset Behavior

The offset of draggable can be processed by Dragger, but if you intend to add animation to offset, for example, when the draggable isn’t drop in a droppable, and onCancelled is invoked, you can write like that:

val offset = remember {
                Animatable(Offset.Zero, Offset.VectorConverter)
            }
            val scope = rememberCoroutineScope()
            val dragRef = dropper.createDraggableRef("name", "info", DraggableEventCallBack(
                onDrag = {
                    scope.launch { offset.snapTo(offset.value + it) }
                },
                onDragStart = {
                    scope.launch { offset.snapTo(offset.value + it) }
                },
                onDropped = {
                    scope.launch { offset.snapTo(Offset.Zero) }
                },
                onCancelled = {
                    scope.launch { offset.animateTo(Offset.Zero) }
                }
            ))
Box(modifier = Modifier.offset {
                        offset.value.let {
                            IntOffset(x = it.x.roundToInt(), y = it.y.roundToInt())
                        }
                }.draggable(dragRef, isSetOffset = false))

You can also do other transform like scale. __But Dropper doesn’t surpport rotation, as the size and location of Draggable may get wrong.

Multiple Draggable and Droppable

Dropper surpports lots of Draggables and Droppables. However, each of thems belong to one Dropper must have a common addition info type. It is the T in Dropper<T>(). Dropper can automatically process every event to Draggable and Droppable.

GitHub

View Github