| page.title=Drag and Drop |
| parent.title=User Interface |
| parent.link=index.html |
| @jd:body |
| |
| <div id="qv-wrapper"> |
| <div id="qv"> |
| <h2>Quickview</h2> |
| <ul> |
| <li> |
| Allow users to move data within your Activity layout using graphical gestures. |
| </li> |
| <li> |
| Supports operations besides data movement. |
| </li> |
| <li> |
| Only works within a single application. |
| </li> |
| <li> |
| Requires API 11. |
| </li> |
| </ul> |
| <h2>In this document</h2> |
| <ol> |
| <li> |
| <a href="#AboutDragging">Overview</a> |
| <ol> |
| <li> |
| <a href="#DragDropLifecycle">The drag/drop process</a> |
| </li> |
| <li> |
| <a href="#AboutDragListeners">The drag event listener and callback method</a> |
| </li> |
| <li> |
| <a href="#AboutDragEvent">Drag events</a> |
| </li> |
| <li> |
| <a href="#AboutDragShadowBuilder"> |
| The drag shadow</a> |
| </li> |
| </ol> |
| </li> |
| <li> |
| <a href="#DesignDragOperation">Designing a Drag and Drop Operation</a> |
| <ol> |
| <li> |
| <a href="#StartDrag">Starting a drag</a> |
| </li> |
| <li> |
| <a href="#HandleStart">Responding to a drag start</a> |
| </li> |
| <li> |
| <a href="#HandleDuring">Handling events during the drag</a> |
| </li> |
| <li> |
| <a href="#HandleDrop">Responding to a drop</a> |
| </li> |
| <li> |
| <a href="#HandleEnd">Responding to a drag end</a> |
| </li> |
| <li> |
| <a href="#RespondEventSample">Responding to drag events: an example</a> |
| </li> |
| </ol> |
| </li> |
| </ol> |
| <h2>Key classes</h2> |
| <ol> |
| <li> |
| {@link android.view.View View} |
| </li> |
| <li> |
| {@link android.view.View.OnLongClickListener OnLongClickListener} |
| </li> |
| <li> |
| {@link android.view.View.OnDragListener OnDragListener} |
| </li> |
| <li> |
| {@link android.view.DragEvent DragEvent} |
| </li> |
| <li> |
| {@link android.view.View.DragShadowBuilder DragShadowBuilder} |
| </li> |
| <li> |
| {@link android.content.ClipData ClipData} |
| </li> |
| <li> |
| {@link android.content.ClipDescription ClipDescription} |
| </li> |
| </ol> |
| <h2>Related Samples</h2> |
| <ol> |
| <li> |
| <a href="{@docRoot}resources/samples/HoneycombGallery/index.html"> |
| Honeycomb Gallery</a>. |
| </li> |
| <li> |
| <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/DragAndDropDemo.html"> |
| DragAndDropDemo.java</a> and |
| <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/DraggableDot.html"> |
| DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.html">Api Demos</a>. |
| </li> |
| </ol> |
| <h2>See also</h2> |
| <ol> |
| <li> |
| <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> |
| </li> |
| <li> |
| <a href="{@docRoot}guide/topics/ui/ui-events.html">Input Events</a> |
| </li> |
| </ol> |
| </div> |
| </div> |
| <p> |
| 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. |
| </p> |
| <p> |
| Although the framework is primarily designed for data movement, you can use |
| it for other UI actions. For example, you could create an app that mixes colors when the user |
| drags a color icon over another icon. The rest of this topic, however, describes the |
| framework in terms of data movement. |
| </p> |
| <h2 id="AboutDragging">Overview</h2> |
| <p> |
| A drag and drop operation starts when the user makes some gesture that you recognize as a |
| signal to start dragging data. In response, your application tells the system that the drag is |
| starting. The system calls back to your application to get a representation of the data |
| being dragged. As the user's finger moves this representation (a "drag shadow") |
| over the current layout, the system sends drag events to the drag event listener objects and |
| drag event callback methods associated with the {@link android.view.View} objects in the layout. |
| Once the user releases the drag shadow, the system ends the drag operation. |
| </p> |
| <p> |
| You create a drag event listener object ("listeners") from a class that implements |
| {@link android.view.View.OnDragListener}. You set the drag event listener object for a View |
| with the View object's |
| {@link android.view.View#setOnDragListener(View.OnDragListener) setOnDragListener()} method. |
| Each View object also has a {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} |
| callback method. Both of these are described in more detail in the section |
| <a href="#AboutDragListeners">The drag event listener and callback method</a>. |
| </p> |
| <p class="note"> |
| <strong>Note</strong>: For the sake of simplicity, the following sections refer to the routine |
| that receives drag events as the "drag event listener", even though it may actually |
| be a callback method. |
| </p> |
| <p> |
| 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. |
| If the user drops the data over a View object, and that View object's listener or callback |
| method has previously told the system that it wants to accept the drop, then the system sends |
| the data to the listener or callback method in a drag event. |
| </p> |
| <p> |
| Your application tells the system to start a drag by calling the |
| {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} |
| method. This tells the system to start sending drag events. The method also sends the data that |
| you are dragging. |
| </p> |
| <p> |
| You can call |
| {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} |
| for any attached View in the current layout. The system only uses the View object to get access |
| to global settings in your layout. |
| </p> |
| <p> |
| Once your application calls |
| {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}, |
| the rest of the process uses events that the system sends to the View objects in your current |
| layout. |
| </p> |
| <h3 id="DragDropLifecycle">The drag/drop process</h3> |
| <p> |
| There are basically four steps or states in the drag and drop process: |
| </p> |
| <dl> |
| <dt> |
| <em>Started</em> |
| </dt> |
| <dd> |
| In response to the user's gesture to begin a drag, your application calls |
| {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} |
| to tell the system to start a drag. The arguments |
| {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} |
| provide the data to be dragged, metadata for this data, and a callback for drawing the |
| drag shadow. |
| <p> |
| The system first responds by calling back to your application to get a drag shadow. It |
| then displays the drag shadow on the device. |
| </p> |
| <p> |
| Next, the system sends a drag event with action type |
| {@link android.view.DragEvent#ACTION_DRAG_STARTED} to the drag event listeners for |
| all the View objects in the current layout. To continue to receive drag events, |
| including a possible drop event, a drag event listener must return <code>true</code>. |
| This registers the listener with the system. Only registered listeners continue to |
| receive drag events. At this point, listeners can also change the appearance of their |
| View object to show that the listener can accept a drop event. |
| </p> |
| <p> |
| If the drag event listener returns <code>false</code>, then it will not receive drag |
| events for the current operation until the system sends a drag event with action type |
| {@link android.view.DragEvent#ACTION_DRAG_ENDED}. By sending <code>false</code>, the |
| listener tells the system that it is not interested in the drag operation and |
| does not want to accept the dragged data. |
| </p> |
| </dd> |
| <dt> |
| <em>Continuing</em> |
| </dt> |
| <dd> |
| The user continues the drag. As the drag shadow intersects the bounding box of a View |
| object, the system sends one or more drag events to the View object's drag event |
| listener (if it is registered to receive events). The listener may choose to |
| alter its View object's appearance in response to the event. For example, if the event |
| indicates that the drag shadow has entered the bounding box of the View |
| (action type {@link android.view.DragEvent#ACTION_DRAG_ENTERED}), the listener |
| can react by highlighting its View. |
| </dd> |
| <dt> |
| <em>Dropped</em> |
| </dt> |
| <dd> |
| The user releases the drag shadow within the bounding box of a View that can accept the |
| data. The system sends the View object's listener a drag event with action type |
| {@link android.view.DragEvent#ACTION_DROP}. The drag event contains the data that was |
| passed to the system in the call to |
| {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} |
| that started the operation. The listener is expected to return boolean <code>true</code> to |
| the system if code for accepting the drop succeeds. |
| <p> |
| Note that this step only occurs if the user drops the drag shadow within the bounding |
| box of a View whose listener is registered to receive drag events. If the user releases |
| the drag shadow in any other situation, no {@link android.view.DragEvent#ACTION_DROP} |
| drag event is sent. |
| </p> |
| </dd> |
| <dt> |
| <em>Ended</em> |
| </dt> |
| <dd> |
| After the user releases the drag shadow, and after the system sends out (if necessary) |
| a drag event with action type {@link android.view.DragEvent#ACTION_DROP}, the system sends |
| out a drag event with action type {@link android.view.DragEvent#ACTION_DRAG_ENDED} to |
| indicate that the drag operation is over. This is done regardless of where the user released |
| the drag shadow. The event is sent to every listener that is registered to receive drag |
| events, even if the listener received the {@link android.view.DragEvent#ACTION_DROP} event. |
| </dd> |
| </dl> |
| <p> |
| Each of these four steps is described in more detail in the section |
| <a href="#DesignDragOperation">Designing a Drag and Drop Operation</a>. |
| </p> |
| <h3 id="AboutDragListeners">The drag event listener and callback method</h3> |
| <p> |
| A View receives drag events with either a drag event listener that implements |
| {@link android.view.View.OnDragListener} or with its |
| {@link android.view.View#onDragEvent(DragEvent)} callback method. |
| When the system calls the method or listener, it passes to them |
| a {@link android.view.DragEvent} object. |
| </p> |
| <p> |
| You will probably want to use the listener in most cases. When you design UIs, you usually |
| don't subclass View classes, but using the callback method forces you to do this in order to |
| override the method. In comparison, you can implement one listener class and then use it with |
| several different View objects. You can also implement it as an anonymous inline class. To |
| set the listener for a View object, call |
| {@link android.view.View#setOnDragListener(android.view.View.OnDragListener) setOnDragListener()}. |
| </p> |
| <p> |
| You can have both a listener and a callback method for View object. If this occurs, |
| the system first calls the listener. The system doesn't call the callback method unless the |
| listener returns <code>false</code>. |
| </p> |
| <p> |
| The combination of the {@link android.view.View#onDragEvent(DragEvent)} method and |
| {@link android.view.View.OnDragListener} is analogous to the combination |
| of the {@link android.view.View#onTouchEvent(MotionEvent) onTouchEvent()} and |
| {@link android.view.View.OnTouchListener} used with touch events. |
| </p> |
| <h3 id="AboutDragEvent">Drag events</h3> |
| <p> |
| The system sends out a drag event in the form of a {@link android.view.DragEvent} object. The |
| object contains an action type that tells the listener what is happening in the drag/drop |
| process. The object contains other data, depending on the action type. |
| </p> |
| <p> |
| To get the action type, a listener calls {@link android.view.DragEvent#getAction()}. There |
| are six possible values, defined by constants in the {@link android.view.DragEvent} class. These |
| are listed in <a href="#table1">table 1</a>. |
| </p> |
| <p> |
| The {@link android.view.DragEvent} object also contains the data that your application provided |
| to the system in the call to |
| {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}. |
| Some of the data is valid only for certain action types. The data that is valid for each action |
| type is summarized in <a href="#table2">table 2</a>. It is also described in detail with |
| the event for which it is valid in the section |
| <a href="#DesignDragOperation">Designing a Drag and Drop Operation</a>. |
| </p> |
| <p class="table-caption" id="table1"> |
| <strong>Table 1.</strong> DragEvent action types |
| </p> |
| <table> |
| <tr> |
| <th scope="col">getAction() value</th> |
| <th scope="col">Meaning</th> |
| </tr> |
| <tr> |
| <td>{@link android.view.DragEvent#ACTION_DRAG_STARTED}</td> |
| <td> |
| A View object's drag event listener receives this event action type just after the |
| application calls |
| {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} and |
| gets a drag shadow. |
| </td> |
| </tr> |
| <tr> |
| <td>{@link android.view.DragEvent#ACTION_DRAG_ENTERED}</td> |
| <td> |
| A View object's drag event listener receives this event action type when the drag shadow |
| has just entered the bounding box of the View. This is the first event action type the |
| listener receives when the drag shadow enters the bounding box. If the listener wants to |
| continue receiving drag events for this operation, it must return boolean |
| <code>true</code> to the system. |
| </td> |
| </tr> |
| <tr> |
| <td>{@link android.view.DragEvent#ACTION_DRAG_LOCATION}</td> |
| <td> |
| A View object's drag event listener receives this event action type after it receives a |
| {@link android.view.DragEvent#ACTION_DRAG_ENTERED} event while the drag shadow is |
| still within the bounding box of the View. |
| </td> |
| </tr> |
| <tr> |
| <td>{@link android.view.DragEvent#ACTION_DRAG_EXITED}</td> |
| <td> |
| A View object's drag event listener receives this event action type after it receives a |
| {@link android.view.DragEvent#ACTION_DRAG_ENTERED} and at least one |
| {@link android.view.DragEvent#ACTION_DRAG_LOCATION} event, and after the user has moved |
| the drag shadow outside the bounding box of the View. |
| </td> |
| </tr> |
| <tr> |
| <td>{@link android.view.DragEvent#ACTION_DROP}</td> |
| <td> |
| A View object's drag event listener receives this event action type when the user |
| releases the drag shadow over the View object. This action type is only sent to a View |
| object's listener if the listener returned boolean <code>true</code> in response to the |
| {@link android.view.DragEvent#ACTION_DRAG_STARTED} drag event. This action type is not |
| sent if the user releases the drag shadow on a View whose listener is not registered, |
| or if the user releases the drag shadow on anything that is not part of the current |
| layout. |
| <p> |
| The listener is expected to return boolean <code>true</code> if it successfully |
| processes the drop. Otherwise, it should return <code>false</code>. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td>{@link android.view.DragEvent#ACTION_DRAG_ENDED}</td> |
| <td> |
| A View object's drag event listener receives this event action type |
| when the system is ending the drag operation. This action type is not necessarily |
| preceded by an {@link android.view.DragEvent#ACTION_DROP} event. If the system sent |
| a {@link android.view.DragEvent#ACTION_DROP}, receiving the |
| {@link android.view.DragEvent#ACTION_DRAG_ENDED} action type does not imply that the |
| drop operation succeeded. The listener must call |
| {@link android.view.DragEvent#getResult()} to get the value that was |
| returned in response to {@link android.view.DragEvent#ACTION_DROP}. If an |
| {@link android.view.DragEvent#ACTION_DROP} event was not sent, then |
| {@link android.view.DragEvent#getResult()} returns <code>false</code>. |
| </td> |
| </tr> |
| </table> |
| <p class="table-caption" id="table2"> |
| <strong>Table 2.</strong> Valid DragEvent data by action type</p> |
| <table> |
| <tr> |
| <th scope="col">{@link android.view.DragEvent#getAction()} value</th> |
| <th scope="col">{@link android.view.DragEvent#getClipDescription()} value</th> |
| <th scope="col">{@link android.view.DragEvent#getLocalState()} value</th> |
| <th scope="col">{@link android.view.DragEvent#getX()} value</th> |
| <th scope="col">{@link android.view.DragEvent#getY()} value</th> |
| <th scope="col">{@link android.view.DragEvent#getClipData()} value</th> |
| <th scope="col">{@link android.view.DragEvent#getResult()} value</th> |
| </tr> |
| <tr> |
| <td>{@link android.view.DragEvent#ACTION_DRAG_STARTED}</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;"> </td> |
| <td style="text-align: center;"> </td> |
| <td style="text-align: center;"> </td> |
| </tr> |
| <tr> |
| <td>{@link android.view.DragEvent#ACTION_DRAG_ENTERED}</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;"> </td> |
| <td style="text-align: center;"> </td> |
| </tr> |
| <tr> |
| <td>{@link android.view.DragEvent#ACTION_DRAG_LOCATION}</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;"> </td> |
| <td style="text-align: center;"> </td> |
| </tr> |
| <tr> |
| <td>{@link android.view.DragEvent#ACTION_DRAG_EXITED}</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;"> </td> |
| <td style="text-align: center;"> </td> |
| <td style="text-align: center;"> </td> |
| <td style="text-align: center;"> </td> |
| </tr> |
| <tr> |
| <td>{@link android.view.DragEvent#ACTION_DROP}</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;"> </td> |
| </tr> |
| <tr> |
| <td>{@link android.view.DragEvent#ACTION_DRAG_ENDED}</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;">X</td> |
| <td style="text-align: center;"> </td> |
| <td style="text-align: center;"> </td> |
| <td style="text-align: center;"> </td> |
| <td style="text-align: center;">X</td> |
| </tr> |
| </table> |
| <p> |
| The {@link android.view.DragEvent#getAction()}, |
| {@link android.view.DragEvent#describeContents()}, |
| {@link android.view.DragEvent#writeToParcel(Parcel,int) writeToParcel()}, and |
| {@link android.view.DragEvent#toString()} methods always return valid data. |
| </p> |
| <p> |
| If a method does not contain valid data for a particular action type, it returns either |
| <code>null</code> or 0, depending on its result type. |
| </p> |
| <h3 id="AboutDragShadowBuilder"> |
| The drag shadow |
| </h3> |
| <p> |
| During a drag and drop operation, the system displays a image that the user drags. |
| For data movement, this image represents the data being dragged. For other operations, the |
| image represents some aspect of the drag operation. |
| </p> |
| <p> |
| The image is called a drag shadow. You create it with methods you declare for a |
| {@link android.view.View.DragShadowBuilder} object, and then pass it to the system when you |
| start a drag using |
| {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}. |
| As part of its response to |
| {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}, |
| the system invokes the callback methods you've defined in |
| {@link android.view.View.DragShadowBuilder} to obtain a drag shadow. |
| </p> |
| <p> |
| The {@link android.view.View.DragShadowBuilder} class has two constructors: |
| </p> |
| <dl> |
| <dt>{@link android.view.View.DragShadowBuilder#View.DragShadowBuilder(View)}</dt> |
| <dd> |
| This constructor accepts any of your application's |
| {@link android.view.View} objects. The constructor stores the View object |
| in the {@link android.view.View.DragShadowBuilder} object, so during |
| the callback you can access it as you construct your drag shadow. |
| It doesn't have to be associated with the View (if any) that the user |
| selected to start the drag operation. |
| <p> |
| If you use this constructor, you don't have to extend |
| {@link android.view.View.DragShadowBuilder} or override its methods. By default, |
| you will get a drag shadow that has the same appearance as the View you pass as an |
| argument, centered under the location where the user is touching the screen. |
| </p> |
| </dd> |
| <dt>{@link android.view.View.DragShadowBuilder#View.DragShadowBuilder()}</dt> |
| <dd> |
| If you use this constructor, no View object is available in the |
| {@link android.view.View.DragShadowBuilder} object (the field is set to <code>null</code>). |
| If you use this constructor, and you don't extend |
| {@link android.view.View.DragShadowBuilder} or override its methods, |
| you will get an invisible drag shadow. |
| The system does <em>not</em> give an error. |
| </dd> |
| </dl> |
| <p> |
| The {@link android.view.View.DragShadowBuilder} class has two methods: |
| </p> |
| <dl> |
| <dt> |
| {@link android.view.View.DragShadowBuilder#onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} |
| </dt> |
| <dd> |
| The system calls this method immediately after you call |
| {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}. Use it |
| to send to the system the dimensions and touch point of the drag shadow. The method has two |
| arguments: |
| <dl> |
| <dt><em>dimensions</em></dt> |
| <dd> |
| A {@link android.graphics.Point} object. The drag shadow width goes in |
| {@link android.graphics.Point#x} and its height goes in |
| {@link android.graphics.Point#y}. |
| </dd> |
| <dt><em>touch_point</em></dt> |
| <dd> |
| A {@link android.graphics.Point} object. The touch point is the location within the |
| drag shadow that should be under the user's finger during the drag. Its X |
| position goes in {@link android.graphics.Point#x} and its Y position goes in |
| {@link android.graphics.Point#y} |
| </dd> |
| </dl> |
| </dd> |
| <dt> |
| {@link android.view.View.DragShadowBuilder#onDrawShadow(Canvas) onDrawShadow()} |
| </dt> |
| <dd> |
| Immediately after the call to |
| {@link android.view.View.DragShadowBuilder#onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} |
| the system calls |
| {@link android.view.View.DragShadowBuilder#onDrawShadow(Canvas) onDrawShadow()} to get the |
| drag shadow itself. The method has a single argument, a {@link android.graphics.Canvas} |
| object that the system constructs from the parameters you provide in |
| {@link android.view.View.DragShadowBuilder#onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} |
| Use it to draw the drag shadow in the provided {@link android.graphics.Canvas} object. |
| </dd> |
| </dl> |
| <p> |
| To improve performance, you should keep the size of the drag shadow small. For a single item, |
| you may want to use a icon. For a multiple selection, you may want to use icons in a stack |
| rather than full images spread out over the screen. |
| </p> |
| <h2 id="DesignDragOperation">Designing a Drag and Drop Operation</h2> |
| <p> |
| This section shows step-by-step how to start a drag, how to respond to events during |
| the drag, how respond to a drop event, and how to end the drag and drop operation. |
| </p> |
| <h3 id="StartDrag">Starting a drag</h3> |
| <p> |
| The user starts a drag with a drag gesture, usually a long press, on a View object. |
| In response, you should do the following: |
| </p> |
| <ol> |
| <li> |
| As necessary, create a {@link android.content.ClipData} and |
| {@link android.content.ClipData.Item} for the data being moved. As part of the |
| ClipData object, supply metadata that is stored in a {@link android.content.ClipDescription} |
| object within the ClipData. For a drag and drop operation that does not represent data |
| movement, you may want to use <code>null</code> instead of an actual object. |
| <p> |
| For example, this code snippet shows how to respond to a long press on a ImageView |
| by creating a ClipData object that contains the tag or label of an |
| ImageView. Following this snippet, the next snippet shows how to override the methods in |
| {@link android.view.View.DragShadowBuilder}: |
| </p> |
| <pre> |
| // Create a string for the ImageView label |
| private static final String IMAGEVIEW_TAG = "icon bitmap" |
| |
| // Creates a new ImageView |
| ImageView imageView = new ImageView(this); |
| |
| // Sets the bitmap for the ImageView from an icon bit map (defined elsewhere) |
| imageView.setImageBitmap(mIconBitmap); |
| |
| // Sets the tag |
| imageView.setTag(IMAGEVIEW_TAG); |
| |
| ... |
| |
| // Sets a long click listener for the ImageView using an anonymous listener object that |
| // implements the OnLongClickListener interface |
| imageView.setOnLongClickListener(new View.OnLongClickListener() { |
| |
| // Defines the one method for the interface, which is called when the View is long-clicked |
| public boolean onLongClick(View v) { |
| |
| // Create a new ClipData. |
| // This is done in two steps to provide clarity. The convenience method |
| // ClipData.newPlainText() can create a plain text ClipData in one step. |
| |
| // Create a new ClipData.Item from the ImageView object's tag |
| ClipData.Item item = new ClipData.Item(v.getTag()); |
| |
| // Create a new ClipData using the tag as a label, the plain text MIME type, and |
| // the already-created item. This will create a new ClipDescription object within the |
| // ClipData, and set its MIME type entry to "text/plain" |
| ClipData dragData = new ClipData(v.getTag(),ClipData.MIMETYPE_TEXT_PLAIN,item); |
| |
| // Instantiates the drag shadow builder. |
| View.DrawShadowBuilder myShadow = new MyDragShadowBuilder(imageView); |
| |
| // Starts the drag |
| |
| v.startDrag(dragData, // the data to be dragged |
| myShadow, // the drag shadow builder |
| null, // no need to use local data |
| 0 // flags (not currently used, set to 0) |
| ); |
| |
| } |
| } |
| </pre> |
| </li> |
| <li> |
| The following code snippet defines {@code myDragShadowBuilder} |
| It creates a drag shadow for dragging a TextView as a small gray rectangle: |
| <pre> |
| private static class MyDragShadowBuilder extends View.DragShadowBuilder { |
| |
| // The drag shadow image, defined as a drawable thing |
| private static Drawable shadow; |
| |
| // Defines the constructor for myDragShadowBuilder |
| public MyDragShadowBuilder(View v) { |
| |
| // Stores the View parameter passed to myDragShadowBuilder. |
| super(v); |
| |
| // Creates a draggable image that will fill the Canvas provided by the system. |
| shadow = new ColorDrawable(Color.LTGRAY); |
| } |
| |
| // Defines a callback that sends the drag shadow dimensions and touch point back to the |
| // system. |
| @Override |
| public void onProvideShadowMetrics (Point size, Point touch) |
| // Defines local variables |
| private int width, height; |
| |
| // Sets the width of the shadow to half the width of the original View |
| width = getView().getWidth() / 2; |
| |
| // Sets the height of the shadow to half the height of the original View |
| height = getView().getHeight() / 2; |
| |
| // The drag shadow is a ColorDrawable. This sets its dimensions to be the same as the |
| // Canvas that the system will provide. As a result, the drag shadow will fill the |
| // Canvas. |
| shadow.setBounds(0, 0, width, height); |
| |
| // Sets the size parameter's width and height values. These get back to the system |
| // through the size parameter. |
| size.set(width, height); |
| |
| // Sets the touch point's position to be in the middle of the drag shadow |
| touch.set(width / 2, height / 2); |
| } |
| |
| // Defines a callback that draws the drag shadow in a Canvas that the system constructs |
| // from the dimensions passed in onProvideShadowMetrics(). |
| @Override |
| public void onDrawShadow(Canvas canvas) { |
| |
| // Draws the ColorDrawable in the Canvas passed in from the system. |
| shadow.draw(canvas); |
| } |
| } |
| </pre> |
| <p class="note"> |
| <strong>Note:</strong> Remember that you don't have to extend |
| {@link android.view.View.DragShadowBuilder}. The constructor |
| {@link android.view.View.DragShadowBuilder#View.DragShadowBuilder(View)} creates a |
| default drag shadow that's the same size as the View argument passed to it, with the |
| touch point centered in the drag shadow. |
| </p> |
| </li> |
| </ol> |
| <h3 id="HandleStart">Responding to a drag start</h3> |
| <p> |
| During the drag operation, the system dispatches drag events to the drag event listeners |
| of the View objects in the current layout. The listeners should react |
| by calling {@link android.view.DragEvent#getAction()} to get the action type. |
| At the start of a drag, this methods returns {@link android.view.DragEvent#ACTION_DRAG_STARTED}. |
| </p> |
| <p> |
| In response to an event with the action type {@link android.view.DragEvent#ACTION_DRAG_STARTED}, |
| a listener should do the following: |
| </p> |
| <ol> |
| <li> |
| Call {@link android.view.DragEvent#getClipDescription()} to get the |
| {@link android.content.ClipDescription}. Use the MIME type methods in |
| {@link android.content.ClipDescription} to see if the listener can accept the data being |
| dragged. |
| <p> |
| If the drag and drop operation does not represent data movement, this may not be |
| necessary. |
| </p> |
| </li> |
| <li> |
| If the listener can accept a drop, it should return <code>true</code>. This tells |
| the system to continue to send drag events to the listener. |
| If it can't accept a drop, it should return <code>false</code>, and the system |
| will stop sending drag events until it sends out |
| {@link android.view.DragEvent#ACTION_DRAG_ENDED}. |
| </li> |
| </ol> |
| <p> |
| Note that for an {@link android.view.DragEvent#ACTION_DRAG_STARTED} event, these |
| the following {@link android.view.DragEvent} methods are not valid: |
| {@link android.view.DragEvent#getClipData()}, {@link android.view.DragEvent#getX()}, |
| {@link android.view.DragEvent#getY()}, and {@link android.view.DragEvent#getResult()}. |
| </p> |
| <h3 id="HandleDuring">Handling events during the drag</h3> |
| <p> |
| During the drag, listeners that returned <code>true</code> in response to |
| the {@link android.view.DragEvent#ACTION_DRAG_STARTED} drag event continue to receive drag |
| events. The types of drag events a listener receives during the drag depend on the location of |
| the drag shadow and the visibility of the listener's View. |
| </p> |
| <p> |
| During the drag, listeners primarily use drag events to decide if they should change the |
| appearance of their View. |
| </p> |
| <p> |
| During the drag, {@link android.view.DragEvent#getAction()} returns one of three |
| values: |
| </p> |
| <ul> |
| <li> |
| {@link android.view.DragEvent#ACTION_DRAG_ENTERED}: |
| The listener receives this when the touch point |
| (the point on the screen underneath the user's finger) has entered the bounding box of the |
| listener's View. |
| </li> |
| <li> |
| {@link android.view.DragEvent#ACTION_DRAG_LOCATION}: Once the listener receives an |
| {@link android.view.DragEvent#ACTION_DRAG_ENTERED} event, and before it receives an |
| A{@link android.view.DragEvent#ACTION_DRAG_EXITED} event, it receives a new |
| {@link android.view.DragEvent#ACTION_DRAG_LOCATION} event every time the touch point moves. |
| The {@link android.view.DragEvent#getX()} and {@link android.view.DragEvent#getY()} methods |
| return the the X and Y coordinates of the touch point. |
| </li> |
| <li> |
| {@link android.view.DragEvent#ACTION_DRAG_EXITED}: This event is sent to a listener that |
| previously received {@link android.view.DragEvent#ACTION_DRAG_ENTERED}, after |
| the drag shadow is no longer within the bounding box of the listener's View. |
| </li> |
| </ul> |
| <p> |
| The listener does not need to react to any of these action types. If the listener returns a |
| value to the system, it is ignored. Here are some guidelines for responding to each of |
| these action types: |
| </p> |
| <ul> |
| <li> |
| In response to {@link android.view.DragEvent#ACTION_DRAG_ENTERED} or |
| {@link android.view.DragEvent#ACTION_DRAG_LOCATION}, the listener can change the appearance |
| of the View to indicate that it is about to receive a drop. |
| </li> |
| <li> |
| An event with the action type {@link android.view.DragEvent#ACTION_DRAG_LOCATION} contains |
| valid data for {@link android.view.DragEvent#getX()} and |
| {@link android.view.DragEvent#getY()}, corresponding to the location of the touch point. |
| The listener may want to use this information to alter the appearance of that part of the |
| View that is at the touch point. The listener can also use this information |
| to determine the exact position where the user is going to drop the drag shadow. |
| </li> |
| <li> |
| In response to {@link android.view.DragEvent#ACTION_DRAG_EXITED}, the listener should reset |
| any appearance changes it applied in response to |
| {@link android.view.DragEvent#ACTION_DRAG_ENTERED} or |
| {@link android.view.DragEvent#ACTION_DRAG_LOCATION}. This indicates to the user that |
| the View is no longer an imminent drop target. |
| </li> |
| </ul> |
| <h3 id="HandleDrop">Responding to a drop</h3> |
| <p> |
| When the user releases the drag shadow on a View in the application, and that View previously |
| reported that it could accept the content being dragged, the system dispatches a drag event |
| to that View with the action type {@link android.view.DragEvent#ACTION_DROP}. The listener |
| should do the following: |
| </p> |
| <ol> |
| <li> |
| Call {@link android.view.DragEvent#getClipData()} to get the |
| {@link android.content.ClipData} object that was originally supplied in the call |
| to |
| {@link android.view.View#startDrag(ClipData, View.DragShadowBuilder, Object, int) startDrag()} |
| and store it. If the drag and drop operation does not represent data movement, |
| this may not be necessary. |
| </li> |
| <li> |
| Return boolean <code>true</code> to indicate that the drop was processed successfully, or |
| boolean <code>false</code> if it was not. The returned value becomes the value returned by |
| {@link android.view.DragEvent#getResult()} for an |
| {@link android.view.DragEvent#ACTION_DRAG_ENDED} event. |
| <p> |
| Note that if the system does not send out an {@link android.view.DragEvent#ACTION_DROP} |
| event, the value of {@link android.view.DragEvent#getResult()} for an |
| {@link android.view.DragEvent#ACTION_DRAG_ENDED} event is <code>false</code>. |
| </p> |
| </li> |
| </ol> |
| <p> |
| For an {@link android.view.DragEvent#ACTION_DROP} event, |
| {@link android.view.DragEvent#getX()} and {@link android.view.DragEvent#getY()} |
| return the X and Y position of the drag point at the moment of the drop, using the coordinate |
| system of the View that received the drop. |
| </p> |
| <p> |
| The system does allow the user to release the drag shadow on a View whose listener is not |
| receiving drag events. It will also allow the user to release the drag shadow |
| on empty regions of the application's UI, or on areas outside of your application. |
| In all of these cases, the system does not send an event with action type |
| {@link android.view.DragEvent#ACTION_DROP}, although it does send out an |
| {@link android.view.DragEvent#ACTION_DRAG_ENDED} event. |
| </p> |
| <h3 id="HandleEnd">Responding to a drag end</h3> |
| <p> |
| Immediately after the user releases the drag shadow, the system sends a |
| drag event to all of the drag event listeners in your application, with an action type of |
| {@link android.view.DragEvent#ACTION_DRAG_ENDED}. This indicates that the drag operation is |
| over. |
| </p> |
| <p> |
| Each listener should do the following: |
| </p> |
| <ol> |
| <li> |
| If listener changed its View object's appearance during the operation, it should reset the |
| View to its default appearance. This is a visual indication to the user that the operation |
| is over. |
| </li> |
| <li> |
| The listener can optionally call {@link android.view.DragEvent#getResult()} to find out more |
| about the operation. If a listener returned <code>true</code> in response to an event of |
| action type {@link android.view.DragEvent#ACTION_DROP}, then |
| {@link android.view.DragEvent#getResult()} will return boolean <code>true</code>. In all |
| other cases, {@link android.view.DragEvent#getResult()} returns boolean <code>false</code>, |
| including any case in which the system did not send out a |
| {@link android.view.DragEvent#ACTION_DROP} event. |
| </li> |
| <li> |
| The listener should return boolean <code>true</code> to the system. |
| </li> |
| </ol> |
| <p> |
| </p> |
| <h3 id="RespondEventSample">Responding to drag events: an example</h3> |
| <p> |
| All drag events are initially received by your drag event method or listener. The following |
| code snippet is a simple example of reacting to drag events in a listener: |
| </p> |
| <pre> |
| // Creates a new drag event listener |
| mDragListen = new myDragEventListener(); |
| |
| View imageView = new ImageView(this); |
| |
| // Sets the drag event listener for the View |
| imageView.setOnDragListener(mDragListen); |
| |
| ... |
| |
| protected class myDragEventListener implements View.OnDragEventListener { |
| |
| // This is the method that the system calls when it dispatches a drag event to the |
| // listener. |
| public boolean onDrag(View v, DragEvent event) { |
| |
| // Defines a variable to store the action type for the incoming event |
| final int action = event.getAction(); |
| |
| // Handles each of the expected events |
| switch(action) { |
| |
| case DragEvent.ACTION_DRAG_STARTED: |
| |
| // Determines if this View can accept the dragged data |
| if (event.getClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) { |
| |
| // As an example of what your application might do, |
| // applies a blue color tint to the View to indicate that it can accept |
| // data. |
| v.setColorFilter(Color.BLUE); |
| |
| // Invalidate the view to force a redraw in the new tint |
| v.invalidate(); |
| |
| // returns true to indicate that the View can accept the dragged data. |
| return(true); |
| |
| } else { |
| |
| // Returns false. During the current drag and drop operation, this View will |
| // not receive events again until ACTION_DRAG_ENDED is sent. |
| return(false); |
| |
| } |
| break; |
| |
| case DragEvent.ACTION_DRAG_ENTERED: { |
| |
| // Applies a green tint to the View. Return true; the return value is ignored. |
| |
| v.setColorFilter(Color.GREEN); |
| |
| // Invalidate the view to force a redraw in the new tint |
| v.invalidate(); |
| |
| return(true); |
| |
| break; |
| |
| case DragEvent.ACTION_DRAG_LOCATION: |
| |
| // Ignore the event |
| return(true); |
| |
| break; |
| |
| case DragEvent.ACTION_DRAG_EXITED: |
| |
| // Re-sets the color tint to blue. Returns true; the return value is ignored. |
| v.setColorFilter(Color.BLUE); |
| |
| // Invalidate the view to force a redraw in the new tint |
| v.invalidate(); |
| |
| return(true); |
| |
| break; |
| |
| case DragEvent.ACTION_DROP: |
| |
| // Gets the item containing the dragged data |
| ClipData.Item item = event.getClipData().getItemAt(0); |
| |
| // Gets the text data from the item. |
| dragData = item.getText(); |
| |
| // Displays a message containing the dragged data. |
| Toast.makeText(this, "Dragged data is " + dragData, Toast.LENGTH_LONG); |
| |
| // Turns off any color tints |
| v.clearColorFilter(); |
| |
| // Invalidates the view to force a redraw |
| v.invalidate(); |
| |
| // Returns true. DragEvent.getResult() will return true. |
| return(true); |
| |
| break; |
| |
| case DragEvent.ACTION_DRAG_ENDED: |
| |
| // Turns off any color tinting |
| v.clearColorFilter(); |
| |
| // Invalidates the view to force a redraw |
| v.invalidate(); |
| |
| // Does a getResult(), and displays what happened. |
| if (event.getResult()) { |
| Toast.makeText(this, "The drop was handled.", Toast.LENGTH_LONG); |
| |
| } else { |
| Toast.makeText(this, "The drop didn't work.", Toast.LENGTH_LONG); |
| |
| }; |
| |
| // returns true; the value is ignored. |
| return(true); |
| |
| break; |
| |
| // An unknown action type was received. |
| default: |
| Log.e("DragDrop Example","Unknown action type received by OnDragListener."); |
| |
| break; |
| }; |
| }; |
| }; |
| </pre> |