Drag and Drop Android
With the Android drag/drop framework, you can allow your users to move data from one View to another View in the current layout using a graphical drag and drop gesture. The framework includes a drag event class, drag listeners, and helper methods and classes.
When you start a drag, you include both the data you are moving and metadata describing this data as part of the call to the system. During the drag, the system sends drag events to the drag event listeners or callback methods of each View in the layout. The listeners or callback methods can use the metadata to decide if they want to accept the data when it is dropped.
Your application tells the system to start a drag by calling the startDrag(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags) method. This tells the system to start sending drag events. The method also sends the data that you are dragging.
Drag events
ACTION_DRAG_STARTED – Received just after the application calls startDrag() and gets a drag shadow.
ACTION_DRAG_ENTERED – Received when the drag shadow has just entered the bounding box of the View
ACTION_DRAG_LOCATION – Received while the drag shadow is still within the bounding box of the View.
ACTION_DRAG_EXITED – Received after the user has moved the drag shadow outside the bounding box of the View
ACTION_DROP – Received when the user releases the drag shadow over the View object.
ACTION_DRAG_ENDED – Received when the system is ending the drag operation.
Drag Shadow
During a drag and drop operation, the system displays a image that the user drags. The image is called a drag shadow. You create it with methods you declare for a View.DragShadowBuilder object, and then pass it to the system when you start a drag using startDrag().
ClipData
For case of data movement in drag and drop, we use ClipData to represent it. It is passed in startDrag() and contains description about data being dragged.
Sample Drag and Drop Application
In our application, we will create four box views and two parent views for drag and drop operations. As soon as any of box views are touched, we will call startDrag() for that view and on getting drop event on any of the left or right parent view, we will detach it from source parent view and add it to target parent view. Lets start creating application step by step.
1. Preparing UI
Create shape drawables which will act as background of our ImageView to give final impersonation to that of above boxes. Create four different colored shapes similar to /res/drawable/box_one.xml as below. Name them as box_one.xml, box_two.xml, box_three.xml and box_four.xml respectively.
1 2 3 4 5 |
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="@android:color/holo_blue_light"/> <corners android:radius="5dp"/> </shape> |
In main activity layout, /res/layout/activity_main.xml, define two LinearLayout to act as left and right target view. Initially, in our layout all four ImageView boxes will be present in left view.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" tools:context="com.androidsrc.draganddrop.MainActivity" > <LinearLayout android:id="@+id/left_view" android:layout_width="0dp" android:layout_height="match_parent" android:layout_margin="10dp" android:layout_weight="1" android:background="@android:color/darker_gray" android:gravity="center_vertical" android:orientation="vertical" > <ImageView android:id="@+id/box_view1" android:layout_width="70dp" android:layout_height="70dp" android:layout_gravity="center_vertical|center_horizontal" android:layout_margin="10dp" android:background="@drawable/box_one" /> <ImageView android:id="@+id/box_view2" android:layout_width="70dp" android:layout_height="70dp" android:layout_gravity="center_vertical|center_horizontal" android:layout_margin="10dp" android:background="@drawable/box_two" /> <ImageView android:id="@+id/box_view3" android:layout_width="70dp" android:layout_height="70dp" android:layout_gravity="center_vertical|center_horizontal" android:layout_margin="10dp" android:background="@drawable/box_three" /> <ImageView android:id="@+id/box_view4" android:layout_width="70dp" android:layout_height="70dp" android:layout_gravity="center_vertical|center_horizontal" android:layout_margin="10dp" android:background="@drawable/box_four" /> </LinearLayout> <LinearLayout android:id="@+id/right_view" android:layout_width="0dp" android:layout_height="match_parent" android:layout_margin="10dp" android:layout_weight="1" android:background="@android:color/darker_gray" android:gravity="center_vertical" android:orientation="vertical" > </LinearLayout> </LinearLayout> |
2. Implementing Functionality
In your launcher application of activity, implement View.OnTouchListener and View.OnDragListener in-order to respond to touch and drag events. Set touch listener to all box view and drag listener to left and right target views. We will keep drag and drop operation very simple. As soon as we get MotionEvent.ACTION_DOWN for any box view, we call startDrag() for this box view. ClipData will be null and LocalView will be same as out touched view as we are just dragging an UI component. On receiving DragEvent.ACTION_DROP, we will detach this view from source and add it to target view.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
package com.androidsrc.draganddrop; import android.app.Activity; import android.os.Bundle; import android.view.DragEvent; import android.view.Menu; import android.view.MenuItem; 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 MainActivity extends Activity implements OnTouchListener, OnDragListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //set ontouch listener for box views findViewById(R.id.box_view1).setOnTouchListener(this); findViewById(R.id.box_view2).setOnTouchListener(this); findViewById(R.id.box_view3).setOnTouchListener(this); findViewById(R.id.box_view4).setOnTouchListener(this); //set ondrag listener for right and left parent views findViewById(R.id.left_view).setOnDragListener(this); findViewById(R.id.right_view).setOnDragListener(this); } @Override public boolean onDrag(View v, DragEvent event) { // TODO Auto-generated method stub if (event.getAction() == DragEvent.ACTION_DROP) { //we want to make sure it is dropped only to left and right parent view View view = (View) event.getLocalState(); if (v.getId() == R.id.left_view || v.getId() == R.id.right_view) { ViewGroup source = (ViewGroup) view.getParent(); source.removeView(view); LinearLayout target = (LinearLayout) v; target.addView(view); } //make view visible as we set visibility to invisible while starting drag view.setVisibility(View.VISIBLE); } return true; } @Override public boolean onTouch(View view, MotionEvent event) { // TODO Auto-generated method stub if (event.getAction() == MotionEvent.ACTION_DOWN) { DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view); view.startDrag(null, shadowBuilder, view, 0); view.setVisibility(View.INVISIBLE); return true; } return false; } } |
3. Build and Run Application
That’s it, we are finished with sample application If you have followed above steps carefully, you will be able to run it. Try dragging boxes from left view and drop them to right view Or vice-versa.