Skip to content

Compose Multiplatform library containing gesture-based utilities

Notifications You must be signed in to change notification settings

susumunoda/compose-gestures

Repository files navigation

Summary

The aim of this library is to provide utilities that simplify gesture-based interactions, starting with easily configured drag-and-drop functionality.

Platforms

This library is compatible with Compose Multiplatform and currently supports the iOS and Android targets.

Drag-and-drop with DragContext

Motivation

In Jetpack Compose, gesture-based behavior is added to composables via Compose modifiers. For instance, the Modifier.draggable modifier can be used to detect when a composable is being dragged in a single orientation. To handle more complex cases of dragging composables, the Modifier.pointerInput modifier is available.

In both of these cases, detection of user input is handled separately from actually moving the dragged composable on the screen; to move the composable, the detected offset must be passed to Modifier.offset. On top of this, there is no default concept of drag-and-drop where a receiving composable (a "drop target") can be configured to receive data from the dragged composable (a "drag target"), nor is there any built-in concept of the current state of the drag or drop targets (e.g. being hovered over).

The DragContext API was created to enable flexible drag-and-drop behavior while encapsulating the complexity of the implementation details so that developers can focus on core app logic instead. Phrased differently, the DragContext API is meant to be a declarative way to specify drag-and-drop behavior — to specify what you want to be dragged and dropped without needing to specify how.

Usage

To use the DragContext API, first create an instance of DragContext<T> where T is the type parameter specifying the type of data that will be dropped into the drop target:

val dragContext = DragContext<Int>()

Next, specify a drag target by wrapping the desired composable in the DragTarget composable, which is a member function of the dragContext instance. For convenience, the withDragContext function is provided so that you can do:

withDragContext(dragContext) {
  DragTarget(data = ...) {
    // Your composable here
  }
}

instead of

dragContext.DragTarget(data = ...) { ... }

The next step is to specify a drop target by wrapping the desired composable in the DropTarget composable, similar to how DragTarget was configured:

withDragContext(dragContext) {
  DropTarget(onDragTargetAdded = { ... }) {
    // Your composable here
  }
}

Note: It is important that the same DragContext instance be used for both the DragTarget and DropTarget. This is because all of the internal state of the drag-and-drop items — e.g. the drag targets' positions, the drop targets' callbacks, etc. — are all contained internally in the DragContext.

Tip: While in this example the dragContext is locally accessible to both the DragTarget and DropTarget calls, this may not be the case in a larger, more complex application. In such cases, the DragContext instance can be provided to deeply nested areas of the application by creating a CompositionLocal. For an example of this, see the susumunoda/word-game repository: where the CompositionLocal is defined, where it is used to set up DragTargets, and where it is used to set up DropTargets.

Reference

TODO

Demos

drag_context_demo_10-10-23.mov

See the source code.

For a more complex example, see susumunoda/word-game.

Future

It is worth noting that the DragContext API does not currently take advantage of the experimental AnchoredDraggable API. It is possible that as that API matures, the DragContext API may also change or possibly no longer be necessary.

About

Compose Multiplatform library containing gesture-based utilities

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages