Version 1.1
Copyright © 2012, 2013 Lars Vogel
06.01.2013
| Revision History | |||
|---|---|---|---|
| Revision 0.1 | 14.02.2012 | Created | |
| Revision History | |||
|---|---|---|---|
| Revision 1.1 | 24.02.2012 - 06.01.2013 | Bugfixes and enhancements | |
Table of Contents
As of Android 4.0 Drag and Drop of
Views
is supported. You register a listener on the
View
and you define other
Views
as possible drop targets, e.g. drop zones.
To use this you register a listener on the
View, e.g. a
OnTouchListener
or a
LongClickListener.
In this method you construct an object of type
ClipData. This object can be used to contain data which can be passed to the
Views
which are defined as drop zones.
The
DragShadowBuilder
allow you specify the look of the dragging operation. Typically you
pass in the
View
directly, which will be shown for the drag operation.
// Assign the touch listener to your view which you want to move findViewById(R.id.myimage1).setOnTouchListener(new MyTouchListener()); // This defines your touch listener private final class MyTouchListener implements OnTouchListener { public boolean onTouch(View view, MotionEvent motionEvent) { if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { ClipData data = ClipData.newPlainText("", ""); DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view); view.startDrag(data, shadowBuilder, view, 0); view.setVisibility(View.INVISIBLE); return true; } else { return false; } } }
A
View
which are used as a drop zone, gets a
OnDragListener
assigned via the
setOnDragListener()
method. In this
OnDragListener
you can evaluate the events and react accordingly.
findViewById(R.id.bottomright).setOnDragListener(new MyDragListener()); class MyDragListener implements OnDragListener { Drawable enterShape = getResources().getDrawable(R.drawable.shape_droptarget); Drawable normalShape = getResources().getDrawable(R.drawable.shape); @Override public boolean onDrag(View v, DragEvent event) { int action = event.getAction(); switch (event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: // Do nothing break; case DragEvent.ACTION_DRAG_ENTERED: v.setBackgroundDrawable(enterShape); break; case DragEvent.ACTION_DRAG_EXITED: v.setBackgroundDrawable(normalShape); break; case DragEvent.ACTION_DROP: // Dropped, reassign View to ViewGroup View view = (View) event.getLocalState(); ViewGroup owner = (ViewGroup) view.getParent(); owner.removeView(view); LinearLayout container = (LinearLayout) v; container.addView(view); view.setVisibility(View.VISIBLE); break; case DragEvent.ACTION_DRAG_ENDED: v.setBackgroundDrawable(normalShape); default: break; } return true; } }
Create a new Android project called de.vogella.android.draganddrop with an activity called DragActivity.
We are going to use XML drawables in this example.
Create the
drawable
folder in your
res
directory. Create the following
shape.xml
file in this
folder.
<?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <stroke android:width="2dp" android:color="#FFFFFFFF" /> <gradient android:angle="225" android:endColor="#DD2ECCFA" android:startColor="#DD000000" /> <corners android:bottomLeftRadius="7dp" android:bottomRightRadius="7dp" android:topLeftRadius="7dp" android:topRightRadius="7dp" /> </shape>
Create the
shape_droptarget.xml
file in the
drawable
folder.
<?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <stroke android:width="2dp" android:color="#FFFF0000" /> <gradient android:angle="225" android:endColor="#DD2ECCFA" android:startColor="#DD000000" /> <corners android:bottomLeftRadius="7dp" android:bottomRightRadius="7dp" android:topLeftRadius="7dp" android:topRightRadius="7dp" /> </shape>
Change the layout of your activity to the following code.
<?xml version="1.0" encoding="utf-8"?> <GridLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:columnCount="2" android:columnWidth="300dp" android:orientation="vertical" android:rowCount="2" android:stretchMode="columnWidth" > <LinearLayout android:id="@+id/topleft" android:layout_width="160dp" android:layout_height="200dp" android:layout_column="0" android:layout_row="0" android:background="@drawable/shape" > <ImageView android:id="@+id/myimage1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_column="0" android:layout_row="0" android:src="@drawable/ic_launcher" /> </LinearLayout> <LinearLayout android:id="@+id/topright" android:layout_width="160dp" android:layout_height="200dp" android:layout_column="1" android:layout_row="0" android:background="@drawable/shape" > <ImageView android:id="@+id/myimage2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_column="0" android:layout_row="0" android:src="@drawable/ic_launcher" /> </LinearLayout> <LinearLayout android:id="@+id/bottomleft" android:layout_width="160dp" android:layout_height="200dp" android:layout_column="0" android:layout_row="1" android:background="@drawable/shape" > <ImageView android:id="@+id/myimage3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_launcher" /> </LinearLayout> <LinearLayout android:id="@+id/bottomright" android:layout_width="160dp" android:layout_height="200dp" android:layout_column="1" android:layout_row="1" android:background="@drawable/shape" > <ImageView android:id="@+id/myimage4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_column="0" android:layout_row="0" android:src="@drawable/ic_launcher" /> </LinearLayout> </GridLayout>
Change your activity class to the following code.
package de.vogella.android.draganddrop; import android.app.Activity; import android.content.ClipData; import android.graphics.drawable.Drawable; 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; public class DragActivity extends Activity {/** Called when the activity is first created. */@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.myimage1).setOnTouchListener(new MyTouchListener()); findViewById(R.id.myimage2).setOnTouchListener(new MyTouchListener()); findViewById(R.id.myimage3).setOnTouchListener(new MyTouchListener()); findViewById(R.id.myimage4).setOnTouchListener(new MyTouchListener()); findViewById(R.id.topleft).setOnDragListener(new MyDragListener()); findViewById(R.id.topright).setOnDragListener(new MyDragListener()); findViewById(R.id.bottomleft).setOnDragListener(new MyDragListener()); findViewById(R.id.bottomright).setOnDragListener(new MyDragListener()); } private final class MyTouchListener implements OnTouchListener { public boolean onTouch(View view, MotionEvent motionEvent) { if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { ClipData data = ClipData.newPlainText("", ""); DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view); view.startDrag(data, shadowBuilder, view, 0); view.setVisibility(View.INVISIBLE); return true; } else { return false; } } } class MyDragListener implements OnDragListener { Drawable enterShape = getResources().getDrawable(R.drawable.shape_droptarget); Drawable normalShape = getResources().getDrawable(R.drawable.shape); @Override public boolean onDrag(View v, DragEvent event) { int action = event.getAction(); switch (event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: // Do nothing break; case DragEvent.ACTION_DRAG_ENTERED: v.setBackgroundDrawable(enterShape); break; case DragEvent.ACTION_DRAG_EXITED: v.setBackgroundDrawable(normalShape); break; case DragEvent.ACTION_DROP: // Dropped, reassign View to ViewGroup View view = (View) event.getLocalState(); ViewGroup owner = (ViewGroup) view.getParent(); owner.removeView(view); LinearLayout container = (LinearLayout) v; container.addView(view); view.setVisibility(View.VISIBLE); break; case DragEvent.ACTION_DRAG_ENDED: v.setBackgroundDrawable(normalShape); default: break; } return true; } } }
If you start this
activity
you should be able to drag the
ImageViews
to another container.

Before posting questions, please see the vogella FAQ. If you have questions or find an error in this article please use the www.vogella.com Google Group. I have created a short list how to create good questions which might also help you.
Android Dialogs standard documentation.
Android ListView and ListActivity
vogella Training Android and Eclipse Training from the vogella team
Android Tutorial Introduction to Android Programming
GWT Tutorial Program in Java and compile to JavaScript and HTML
Eclipse RCP Tutorial Create native applications in Java
JUnit Tutorial Test your application
Git Tutorial Put everything you have under distributed version control system