Android Drag and Drop Tutorial: Moving Views and Data

Learn how to use Android’s drag-and-drop framework to enable an advanced gesture-based user experience. By Kushal Kumar R.

4.8 (4) · 2 Reviews

Download materials
Save for later

Ready to delight your users with the Android drag-and-drop framework?

Drag and drop seems like magic because it gives your app users the capability to move UI elements by performing gestures on the screen. In this tutorial, you’ll learn about the events and actions that drive this framework so you can become a drag-and-drop wizard! You’ll create an app named Masky that lets you drag a mask onto the screen and drop it over an unmasked face. More specifically, you’ll learn how to:

  1. Design drag-and-drop operations.
  2. Customize the drag shadow.
  3. Respond to drag-and-drop events.
  4. Move a view — the mask — across the screen to its new drop area.
  5. Check if the mask view is on the face.
Note: This tutorial assumes you have a basic working knowledge of the Kotlin programming language and Android development. If you need to brush up on your skills, check out our Android and Kotlin for Beginners learning path or our books, Android Apprentice and Kotlin Apprentice.

You’ll start by looking at the starter project and learning how drag and drop works.

Getting Started

Download the starter project by clicking the Download Materials button at the top or bottom of the tutorial.

Open the starter project in Android Studio. Build and run. You’ll see the following screen:

Masky Drag and Drop Starter Project

The app currently shows the mask and the unmasked face, but you can’t do anything with them yet. The starter project is a clean slate, ready for you to start working on it. As you follow along with the tutorial, you’ll see the app take shape.

The Drag-and-Drop Process

Android’s drag-and-drop framework lets users move data and views using graphical gestures. Users can drag and drop data across views within the same app or even from one app to another, if they have multi-window mode enabled.

In this tutorial, you’ll use framework internals like drag event classes and drag listeners to design your own drag-and-drop operations.

The Four Drag-and-Drop States

The drag-and-drop process consists of four states:

  1. Started
  2. Continuing
  3. Dropped
  4. Ended

Now, you’ll take a look at each of these states, as the diagram below illustrates.

Started State

When the user makes a UI gesture that your app recognizes as a trigger, such as a long click, the drag process begins. The app provides drag data along with a drag shadow callback as arguments to the system via startDragAndDrop().

Note: To start a drag, use startDragAndDrop() for Nougat devices and newer. For pre-Nougat devices use startDrag().

The system first displays a drag shadow, which can be either a shadow or an actual draggable view, on the device. It uses the action type ACTION_DRAG_STARTED to dispatch a drag event to all the registered drag event listeners in the current layout.

The drag event listener returns a Boolean true to continue receiving drag events. If the listener only needs to know when the drag has ended, it can opt out of receiving the drag data by returning false instead. This ensures that the listener will only receive the final drag event with the action type ACTION_DRAG_ENDED.

  • getClipData()
  • getX()
  • getY()
  • getResult()
Note: The following DragEvent methods are not valid on the ACTION_DRAG_STARTED event action type:
  • getClipData()
  • getX()
  • getY()
  • getResult()

Continuing State

As the user continues to drag, the drag process enters the continuing state.

In this state, the system dispatches one or more drag events to registered drag event listeners.

For example, as the drag shadow enters the bounding box of the view that is registered for drag events, the system dispatches the action type ACTION_DRAG_ENTERED to the listener.

After receiving an ACTION_DRAG_ENTERED event and before it can receive an ACTION_DRAG_EXITED event, the listener receives a new ACTION_DRAG_LOCATION event as the drag continues. Here you can retrieve the current x, y coordinates of the draggable view.

Likewise, when the drag shadow leaves the bounding box, an ACTION_DRAG_EXITED action type is sent to the listener.

In your app, you’ll only deal with the ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED action types.

Dropped State

When the user releases the drag shadow over a view that’s registered for drag events, the system dispatches a drag event with action type ACTION_DROP.

You retrieve data passed from this drag event as arguments in startDragAndDrop()/startDrag().

Ended State

Finally, the system wraps up the drag operation by dispatching a drag event with the action type ACTION_DRAG_ENDED.

After receiving ACTION_DRAG_ENDED, each drag event listener should:

  1. Reset all the state or UI changes you made during the drag operation.
  2. Return a Boolean true.
  3. Optionally, check the drop success status by invoking getResult().

Now that you have a theoretical understanding of Android drag-and-drop operations, it’s time to apply this knowledge in a real app!

Designing a Drag Operation

Now, it’s time to implement drag and drop in Masky. You’ll program the app to let the user drag the mask around the screen and drop it over an unmasked face. After the user drops the mask, a toast message will notify them about whether the mask is on or off the face.

For this app, you’ll use a long click to start the drag operation.

Adding a Drag Shadow

The system displays a placeholder image to represent the actual view/data during a drag operation. This placeholder image representation is the drag shadow.

drag shadow android

To create a drag shadow builder, you subclass View.DragShadowBuilder. You can then pass the builder as an argument to the system when you start a drag operation using startDragAndDrop() or startDrag().

The system then uses the drag shadow builder to invoke its callback methods to obtain a drag shadow.

If you don’t want to display a drag shadow, you don’t have to. You control whether the drop shadow displays or not by picking the appropriate View.DragShadowBuilder constructor:

  1. View.DragShadowBuilder(view): Accepts a View object to create a drag shadow that looks similar to the view object the user is dragging. To customize your drag shadow, you can subclass this class and override the methods, as you’ll see later.
  2. View.DragShadowBuilder(): This drag shadow builder has no parameters and will give you an invisible drag shadow. As the user drags the view, there’s no visual cue that the drag is in progress until it ends.

Your next step is to customize the drag shadow to match your requirements by subclassing View.DragShadowBuilder(view).