I am a creature
of habit — if something isn’t
broke, I don’t try to fix it. Unfortunately, that attitude can make it easy in the Android world to
never get your hands on really cool features and APIs. Slick functionality gets added to
the platform often without any real fanfare. Unless you happen to be at Google I/O for the unveiling or come across
a real-world requirement, it’s easy for things to get under the radar.

Recently, I ran across this with Android’s drag and drop classes. The capability has been around since Ice Cream Sandwich, but I never needed it, so I didn’t bother to poke at it. Then I had a customer
requirement and, after only 15 minutes of prototyping, I was marveling at how easy it is to use the API.

This tutorial shows how to quickly add the useful drag and drop functionality to your next app. Follow along with the step-by-step tutorial,
or, download and import the entire project directly into Eclipse.

1. Create a new project in Eclipse. You need to target Android 4.0 or
better.

2. In the /res folder, create a new directory called
drawable. I added the XML
code to draw three circles: one red, one green, and one blue.

red_ball.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" >
<stroke
android:width="4dp"
android:color="#FF0000" />
<gradient android:startColor="#FFFF0000" android:endColor="#80FF0000"
android:angle="270"/>
</shape>

green_ball.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" >
<stroke
android:width="4dp"
android:color="#00FF00" />
<gradient android:startColor="#FF00FF00" android:endColor="#8000FF00"
android:angle="270"/>
</shape>

blue_ball.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" >
<stroke
android:width="4dp"
android:color="#0000FF" />
<gradient android:startColor="#FF0000FF" android:endColor="#800000FF"
android:angle="270"/>
</shape>

3. Create the activity_main.xml
layout in our /res/layout folder. The layout consists of an outer linear layout and two inner ones. We start by placing all three
images in the top container.

activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Drag-N-Drop Demo"
android:textSize="20sp"
android:padding="10dp"
android:layout_gravity="center"/>

<LinearLayout
android:id="@+id/top_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight=".5"
android:background="#000000"
android:layout_margin="20dp"
android:orientation="horizontal"
android:gravity="center">

<ImageView
android:id="@+id/red_ball"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="10dp"
android:src="@drawable/red_ball" />

<ImageView
android:id="@+id/green_ball"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="10dp"
android:src="@drawable/green_ball" />

<ImageView
android:id="@+id/blue_ball"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="10dp"
android:src="@drawable/blue_ball" />

</LinearLayout>

<LinearLayout
android:id="@+id/bottom_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight=".5"
android:background="#000000"
android:layout_margin="20dp"
android:orientation="horizontal"
android:gravity="center">

</LinearLayout>

</LinearLayout>

4. Now comes the best part. In our /src/MainActivity.java file, create a new activity that implements both the on touch listener and the on
drag listener. In the on create, we
register our images with the touch listener and the containers with the drag
listener. The on touch listener
uses Android’s shadow builder class to create a draggable copy of the original
view, and the on drag listener is responsible for removing the view from the
original layout and adding it to the new one. Ta-da!

MainActivity.java
package com.authorwjf.dragndrop;

import android.os.Bundle;
import android.view.DragEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.OnDragListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.app.Activity;

public class MainActivity extends Activity implements OnTouchListener, OnDragListener {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.red_ball).setOnTouchListener(this);
findViewById(R.id.green_ball).setOnTouchListener(this);
findViewById(R.id.blue_ball).setOnTouchListener(this);
findViewById(R.id.top_container).setOnDragListener(this);
findViewById(R.id.bottom_container).setOnDragListener(this);
}

@Override
public boolean onTouch(View v, MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_DOWN) {
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
v.startDrag(null, shadowBuilder, v, 0);
v.setVisibility(View.INVISIBLE);
return true;
} else {
return false;
}
}

@Override
public boolean onDrag(View v, DragEvent e) {
if (e.getAction()==DragEvent.ACTION_DROP) {
View view = (View) e.getLocalState();
ViewGroup from = (ViewGroup) view.getParent();
from.removeView(view);
LinearLayout to = (LinearLayout) v;
to.addView(view);
view.setVisibility(View.VISIBLE);
}
return true;
}

}

At this point, the apk should be ready to compile and
run (Figure A). Drag a ball from one
container and drop it into another. Now put it back. Isn’t that
cool?

Figure A

In the past, I tended to avoid drag and drop user interface designs because I
imagined it involved a great deal of complexity. After getting a little experience with Android’s implementation,
you can bet I’ll be using it in future projects.