Android optimize

Try Android's useful drag and drop API

The mobile space changes at a dizzying pace, making it difficult to keep up with the latest features. Android 4.0's drag-and-drop support is one enhancement worth noting.

android_ice_cream_sandwich__thumb_091113.jpg
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

Android_drag_n_drop_091113.png

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.


About

William J Francis began programming computers at age eleven. Specializing in embedded and mobile platforms, he has more than 20 years of professional software engineering under his belt, including a four year stint in the US Army's Military Intellige...

1 comments