Quantcast
Channel: Envato Tuts+ Code - Mobile Development
Viewing all articles
Browse latest Browse all 1836

Android SDK: Implementing Drag-and-Drop Functionality

$
0
0

The drag-and-drop facility on the Android SDK is an interaction feature many apps can benefit from and getting started is straightforward. In this tutorial, we will implement a basic drag-and-drop operation, making clear what additional options you have for your own projects!

The simple app we will build is going to allow the user to drag a list of items into order of preference. To the user it will appear that a visible UI item is being dragged to a different location. However, in reality the data associated with one Android View is being moved to another View. You are of course free to use the code in any app you are working on, but you will need to set a minimum SDK version of 11 to use the drag and drop processing.


Step 1: Create and Design the App

Create a new Android project in Eclipse. Enter the application settings of your choice, being sure to create a blank Activity and layout for it. Before we get started on the drag and drop functionality let’s get the layout sorted. We won’t be spending much time on the design so that we can focus on the functional part of the app.

In the layout file you specified when creating the project, enter a Linear Layout outline, replacing any existing content:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:orientation="vertical"
	android:padding="10dp"
	android:paddingLeft="50dp"
	android:paddingRight="50dp" >
</LinearLayout>

Inside the Linear Layout, begin with a small informative Text View:

<TextView
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:gravity="center"
	android:paddingBottom="10dp"
	android:text="@string/intro" />

Add the specified string to your application “res/values/strings.xml” file:

<string name="intro">Place these foods in your order of preference.</string>

While you have the strings file open, add the following three items:

<string name="option_1">Apple</string>
<string name="option_2">Cake</string>
<string name="option_3">Cheese</string>

These strings will be displayed on the items users will drag. There will be three slots for users to drag them onto, so add strings for labels on those next:

<string name="choice_1">Most favorite</string>
<string name="choice_2">-</string>
<string name="choice_3">Least favorite</string>

As you can imagine, in a real app these data items may be read in from a source or stored as XML resources, we are only including them “hard-coded” in this way for demonstration. Back in the layout file, add the first set of Text Views to represent the draggable items:

<TextView
	android:id="@+id/option_1"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:layout_margin="5dp"
	android:background="@drawable/option"
	android:gravity="center"
	android:text="@string/option_1"
	android:textStyle="bold" />
    <TextView
	android:id="@+id/option_2"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:layout_margin="5dp"
	android:background="@drawable/option"
	android:gravity="center"
	android:text="@string/option_2"
	android:textStyle="bold" />
    <TextView
	android:id="@+id/option_3"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:layout_margin="5dp"
	android:background="@drawable/option"
	android:gravity="center"
	android:text="@string/option_3"
	android:textStyle="bold" />

Each of these has an ID so that we can refer to it in the Activity class. We also use the strings we defined. We will create the background drawable soon. Next add the three Text Views onto which the draggable items can be dropped:

<TextView
	android:id="@+id/choice_1"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:layout_margin="5dp"
	android:background="@drawable/choice"
	android:gravity="center"
	android:text="@string/choice_1" />
    <TextView
	android:id="@+id/choice_2"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:layout_margin="5dp"
	android:background="@drawable/choice"
	android:gravity="center"
	android:text="@string/choice_2" />
    <TextView
	android:id="@+id/choice_3"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:layout_margin="5dp"
	android:background="@drawable/choice"
	android:gravity="center"
	android:text="@string/choice_3" />

These also use IDs and string resources. In your application “res/drawables” folder, or folders, create the first background drawable we specified for the draggable Text Views. Select the drawables folder(s) and choose “File”, “New”, “File” – enter “option.xml” as the file name to match what we included in the layout. Insert the following code into the drawables file, defining the background shape:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
	android:dither="true" >
	<solid android:color="#ff00ccff" />
	<corners android:radius="2dp" />
	<stroke
		android:width="2dp"
		android:color="#ff0099cc" />
	<padding
		android:bottom="5dp"
		android:left="10dp"
		android:right="10dp"
		android:top="5dp" />
</shape>

Now create another drawables file, naming it “choice.xml”, this time and entering the following shape:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
	android:dither="true" >
	<solid android:color="#ffffff99" />
	<corners android:radius="2dp" />
	<stroke
		android:dashGap="4dp"
		android:dashWidth="2dp"
		android:width="2dp"
		android:color="#ffffff00" />
	<padding
		android:bottom="5dp"
		android:left="5dp"
		android:right="5dp"
		android:top="5dp" />
</shape>

You can of course change any aspects of the user interface design to suit yourself.

App Initial Screen

Step 2: Setup the Activity

Let’s turn to the app functionality – open your Activity class. Your class will need the following imports, added before the opening class declaration line:

import android.os.Bundle;
import android.app.Activity;
import android.content.ClipData;
import android.graphics.Typeface;
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.widget.TextView;

Inside the class declaration, before the onCreate method (which Eclipse should have automatically filled in for you), add some instance variables:

private TextView option1, option2, option3, choice1, choice2, choice3;

These will allow us to refer to the Text Views we created. Inside the onCreate method, after the existing code, retrieve these UI items as follows:

//views to drag
option1 = (TextView)findViewById(R.id.option_1);
option2 = (TextView)findViewById(R.id.option_2);
option3 = (TextView)findViewById(R.id.option_3);
//views to drop onto
choice1 = (TextView)findViewById(R.id.choice_1);
choice2 = (TextView)findViewById(R.id.choice_2);
choice3 = (TextView)findViewById(R.id.choice_3);

We use the ID attributes included in the layout XML.


Step 3: Create a Touch Listener Class

To use drag and drop within the Activity, we will create two inner classes. These classes will implement the Android interfaces required for dragging and dropping. Start by creating a class declaration outline for a Touch Listener, after the Activity onCreate method:

private final class ChoiceTouchListener implements OnTouchListener {
}

This class will allow the app to detect users touching particular Views, treating a touch as the beginning of a drag operation. Inside the class, add the onTouch method:

public boolean onTouch(View view, MotionEvent motionEvent) {
}

Next check what Motion Event has triggered the onTouch method:

if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
	//setup drag
	return true;
}
else {
	return false;
}

We are only interested in cases where the user has touched the View to drag it, so inside the if statement we will setup the drag operation. Before the “return true” statement, prepare the drag as follows:

ClipData data = ClipData.newPlainText("", "");
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);

This code is pretty standard, as we only need default behavior. However, you can amend this to tailor various aspects of the drag if you need to. You can alter the shadow builder code to set the appearance of the View during the drag. You can also alter the Clip Data if you need finer control over the data being dragged between Views. Now we can start the drag using these details:

//start dragging the item touched
view.startDrag(data, shadowBuilder, view, 0);

If you only need a basic drag and drop process you do not need to worry too much about the details of the Touch Listener.


Step 4: Create a Drag Listener Class

We’ve created the listener class for dragging, now we need one for dropping. After the Touch Listener class, add a Drag Listener class declaration:

private class ChoiceDragListener implements OnDragListener {
}

Add the onDrag method inside this new class:

@Override
public boolean onDrag(View v, DragEvent event) {
	//handle drag events
	return true;
}

This is where we respond to drag events. The Drag Listener can be used to detect and respond to various stages of the drag, each handled within a switch/case statement. Add it inside the onDrag method, before the return statement as follows:

switch (event.getAction()) {
	case DragEvent.ACTION_DRAG_STARTED:
		//no action necessary
		break;
	case DragEvent.ACTION_DRAG_ENTERED:
		//no action necessary
		break;
	case DragEvent.ACTION_DRAG_EXITED:
		//no action necessary
		break;
	case DragEvent.ACTION_DROP:
		//handle the dragged view being dropped over a drop view
		break;
	case DragEvent.ACTION_DRAG_ENDED:
		//no action necessary
		break;
	default:
		break;
}

Most of the drag events are not relevant to this app, however you can use them if you need more detailed control. We will add to the ACTION_DROP section later.


Step 5: Add Listeners to the Text Views

We have Touch and Drag Listener classes defined, now we need to add instances of them to the Views we are dragging and dropping with. Back in the onCreate method, after the existing code, first add Touch Listeners to the three Text Views users will be able to drag:

//set touch listeners
option1.setOnTouchListener(new ChoiceTouchListener());
option2.setOnTouchListener(new ChoiceTouchListener());
option3.setOnTouchListener(new ChoiceTouchListener());

Now add Drag Listeners to the three Views dragged items will be able to be dropped on:

//set drag listeners
choice1.setOnDragListener(new ChoiceDragListener());
choice2.setOnDragListener(new ChoiceDragListener());
choice3.setOnDragListener(new ChoiceDragListener());

We implement an instance of the Touch or Drop classes we created for each of the Text Views. Users will be able to drag any of the top three Text Views onto any of the bottom three.

App While Dragging

Step 6: Handle Drops

Now we have the app setup for users to drag and drop items, we just have to define what should happen when an item is dropped on one of the bottom three Views. Back in your Drag Listener class, in the ACTION_DROP case statement (before the break), first get a reference to the View being dropped:

//handle the dragged view being dropped over a target view
View view = (View) event.getLocalState();

This represents whichever one of the top three Text Views the user has dragged. Since they have successfully dropped it onto one of the bottom three Views, we can stop displaying it in its original position:

//stop displaying the view where it was before it was dragged
view.setVisibility(View.INVISIBLE);

The onDrag method also receives a parameter representing the target View that the dragged item is being dropped on, so cast it as a Text View:

//view dragged item is being dropped on
TextView dropTarget = (TextView) v;

Let’s also cast the dropped View to a Text View:

//view being dragged and dropped
TextView dropped = (TextView) view;

We can now use these to update the text displayed in the bottom area:

//update the text in the target view to reflect the data being dropped
dropTarget.setText(dropped.getText());

Now the text from the dragged View is displayed within the View it was dropped onto. Let’s make it bold to distinguish it from the still vacant spots:

//make it bold to highlight the fact that an item has been dropped
dropTarget.setTypeface(Typeface.DEFAULT_BOLD);

This is how the app appears after the user drags the “Apple” item to the bottom position in the list:

App After Drag and Drop

Step 7: Handle Duplicate Drops

The basic functionality is now complete, but let’s enhance this a little by handling cases in which the user drops more than one item onto the same slot.

We can keep a record of which item is currently dropped into each View in the bottom section using tags. When an item is dropped onto one of the target Views, we can set a tag representing the ID of the View being dropped. Each time we go to drop an item, we can first check whether the target View has a tag representing a View already dropped there. If there is one there, we can simply set its original View back to visible in the top section so that the user can drag it over again, since it is being replaced in the bottom list.

Still inside the ACTION_DROP section, check whether the current target View has a tag set:

//if an item has already been dropped here, there will be a tag
Object tag = dropTarget.getTag();

We only want to reset one of the original Views back visible if there is a tag set:

//if there is already an item here, set it back visible in its original place
if(tag!=null)
{
	//the tag is the view id already dropped here
	int existingID = (Integer)tag;
	//set the original view visible again
	findViewById(existingID).setVisibility(View.VISIBLE);
}

Now we can update the tag to represent the new View data that has been dropped here:

//set the tag in the target view to the ID of the view being dropped
dropTarget.setTag(dropped.getId());

This allows the user to change their mind by dropping items on top of existing items and still make a selection for the items previously dropped.

App After Completion of Drag and Drop

Conclusion

That’s our basic app complete. There are lots of ways in which you could enhance this app. For example, you could also allow users to drag Views from the bottom section after they have been dropped there, either to a different position in the bottom section or back to a position in the top section. To do this you would need to add both Touch and Drag Listeners to all Text Views in the top and bottom sections, so the logic is a little more complex. You could also enhance the app by reading the data in dynamically, or by creating custom designs for different stages of the drag and drop process. Whatever you do, make sure you test your drag and drop operations thoroughly.


Viewing all articles
Browse latest Browse all 1836

Trending Articles