DropHelper for simplified drag-and-drop

The DropHelper class simplifies implementation of drag-and-drop capabilities. A member of the Jetpack DragAndDrop library, DropHelper provides backward compatibility down to API level 24.

Use DropHelper to specify drop targets, customize drop target highlighting, and define how dropped data is handled.

Set drag source

To get started, create DragStartHelper with drag source view and OnDragStartListener.

In OnDragStartListener, override method onDragStart(). Create a ClipData object and ClipData.Item object for the data being moved. As part of the ClipData, supply metadata that is stored in a ClipDescription object within the ClipData. For a drag-and-drop operation that doesn't represent data movement, you might want to use null instead of an actual object.

Kotlin

DragStartHelper(draggableView)
    { view: View, _: DragStartHelper ->
        val item = ClipData.Item(view.tag as? CharSequence)
        val dragData = ClipData(
            view.tag as? CharSequence,
            arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN),
            item
        )
        view.startDragAndDrop(
            dragData,
            View.DragShadowBuilder(view),
            null,
            0
        )
    }.attach()

Java

new DragStartHelper(draggableView, new DragStartHelper.OnDragStartListener() {
    @Override
    public void onDragStart(View view, DragStartHelper helper) {
        CharSequence tag = (CharSequence) view.getTag();
        ClipData.Item item = new ClipData.Item(tag);
        ClipData dragData = new ClipData(
          tag, new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}, item);
        view.startDragAndDrop(
          dragData, new View.DragShadowBuilder(view), null, 0);
    }
});

Specify drop targets

When a user release a drop shadow over a view, the view needs to be configured properly to accept the data and respond correctly.

DropHelper.configureView() is a static, overloaded method that lets you specify drop targets. Its parameters include the following:

For example, to create a drop target that accepts images, use either of the following method calls:

Kotlin

configureView(
    myActivity,
    targetView,
    arrayOf("image/*"),
    options,
    onReceiveContentListener)

// or

configureView(
    myActivity,
    targetView,
    arrayOf("image/*"),
    onReceiveContentListener)

Java

DropHelper.configureView(
    myActivity,
    targetView,
    new String[] {"image/*"},
    options,
    onReceiveContentlistener);

// or

DropHelper.configureView(
    myActivity,
    targetView,
    new String[] {"image/*"},
    onReceiveContentlistener);

The second call omits the drop target configuration options, in which case the drop target highlight color is set to the theme's secondary (or accent) color, the highlight corner radius is set to 16 dp, and the list of EditText components is empty. See the following section for details.

Configure drop targets

The DropHelper.Options inner class lets you configure drop targets. Provide an instance of the class to the DropHelper.configureView(Activity, View, String[], Options, OnReceiveContentListener) method. See the previous section for more information.

Customize drop target highlighting

DropHelper configures drop targets to display a highlight as users drag content over the targets. DropHelper provides default styling, and DropHelper.Options lets you set the color of the highlight and specify the corner radius of the highlight's rectangle.

Use the DropHelper.Options.Builder class to create a DropHelper.Options instance and set configuration options, as shown in the following example:

Kotlin

val options: DropHelper.Options = DropHelper.Options.Builder()
                                      .setHighlightColor(getColor(R.color.purple_300))
                                      .setHighlightCornerRadiusPx(resources.getDimensionPixelSize(R.dimen.drop_target_corner_radius))
                                      .build()

Java

DropHelper.Options options = new DropHelper.Options.Builder()
                                     .setHighlightColor(getColor(R.color.purple_300))
                                     .setHighlightCornerRadiusPx(getResources().getDimensionPixelSize(R.dimen.drop_target_corner_radius))
                                     .build();

Handle EditText components in drop targets

DropHelper also controls focus within the drop target when the target contains editable text fields.

Drop targets can be a single view or a view hierarchy. If the drop target view hierarchy contains one or more EditText components, provide a list of the components to DropHelper.Options.Builder.addInnerEditTexts(EditText...) to ensure that drop target highlighting and text data handling work correctly.

DropHelper prevents EditText components within the drop target view hierarchy from stealing focus from the containing view during drag interactions.

Also, if the drag-and-drop ClipData includes text and URI data, DropHelper selects one of the EditText components in the drop target to handle the text data. Selection is based on the following order of precedence:

  1. The EditText on which the ClipData is dropped.
  2. The EditText that contains the text cursor (caret).
  3. The first EditText provided to the call to DropHelper.Options.Builder.addInnerEditTexts(EditText...).

To set an EditText as the default text data handler, pass the EditText as the first argument of the call to DropHelper.Options.Builder.addInnerEditTexts(EditText...). For example, if your drop target handles images but contains editable text fields T1, T2, and T3, make T2 the default as follows:

Kotlin

val options: DropHelper.Options = DropHelper.Options.Builder()
                                      .addInnerEditTexts(T2, T1, T3)
                                      .build()

Java

DropHelper.Options options = new DropHelper.Options.Builder()
                                     .addInnerEditTexts(T2, T1, T3)
                                     .build();

Handle data in drop targets

The DropHelper.configureView() method accepts an OnReceiveContentListener that you create to handle the drag-and-drop ClipData. The drag-and-drop data is provided to the listener in a ContentInfoCompat object. Text data is present in the object. Media, such as images, is represented by URIs.

The OnReceiveContentListener also handles data provided to the drop target by user interactions other than drag-and-drop—such as copy and paste—when DropHelper.configureView() is used to configure the following types of views:

  • All views, if the user is running Android 12 or higher.
  • AppCompatEditText, if the user is running a version of Android down to Android 7.0.

MIME types, permissions, and content validation

The MIME type checking by DropHelper is based on the drag-and-drop ClipDescription, which is created by the app providing the drag-and-drop data. Validate the ClipDescription to ensure the MIME types are set correctly.

DropHelper requests all access permissions for content URIs contained in the drag-and-drop ClipData. For more information, see DragAndDropPermissions. The permissions let you resolve the content URIs when processing the drag-and-drop data.

DropHelper doesn't validate the data returned by content providers when resolving URIs in the dropped data. Check for null and verify the correctness of any resolved data.