Android SDK: Implementing Drag-and-Drop Functionality

原文:http://mobile.tutsplus.com/tutorials/android/android-sdk-implementing-drag-and-drop-functionality/

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:

<LinearLayoutxmlns: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:

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

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

<stringname="option_1">Apple</string>

<stringname="option_2">Cake</string>

<stringname="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:

<stringname="choice_1">Most favorite</string>

<stringname="choice_2">-</string>

<stringname="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">

    <solidandroid:color="#ff00ccff"/>

    <cornersandroid: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">

    <solidandroid:color="#ffffff99"/>

    <cornersandroid: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 ActivityonCreate method:

private final class ChoiceTouchListenerimplementsOnTouchListener {

}

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 theonTouch 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

    returntrue;

}

else {

    returnfalse;

}

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

ClipData data = ClipData.newPlainText("","");

DragShadowBuilder shadowBuilder =newView.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 implementsOnDragListener {

}

Add the onDrag method inside this new class:

@Override

public boolean onDrag(View v, DragEvent event) {

    //handle drag events

    returntrue;

}

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 theonDrag method, before the return statement as follows:

switch (event.getAction()) {

    caseDragEvent.ACTION_DRAG_STARTED:

        //no action necessary

        break;

    caseDragEvent.ACTION_DRAG_ENTERED:

        //no action necessary

        break;

    caseDragEvent.ACTION_DRAG_EXITED:

        //no action necessary

        break;

    caseDragEvent.ACTION_DROP:

        //handle the dragged view being dropped over a drop view

        break;

    caseDragEvent.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 theACTION_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 theonCreate 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(newChoiceTouchListener());

option2.setOnTouchListener(newChoiceTouchListener());

option3.setOnTouchListener(newChoiceTouchListener());

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

//set drag listeners

choice1.setOnDragListener(newChoiceDragListener());

choice2.setOnDragListener(newChoiceDragListener());

choice3.setOnDragListener(newChoiceDragListener());

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 theACTION_DROP case statement (before thebreak), 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

    intexistingID = (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.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值