Scott Main | b10b48f | 2011-09-13 16:40:52 -0700 | [diff] [blame] | 1 | page.title=Drag and Drop |
Scott Main | 64461bf | 2013-04-11 19:32:08 -0700 | [diff] [blame] | 2 | page.tags="clipdata","dragevent","onlongclicklistener" |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 3 | @jd:body |
Scott Main | 2a1b706 | 2011-02-22 14:43:41 -0800 | [diff] [blame] | 4 | |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 5 | <div id="qv-wrapper"> |
| 6 | <div id="qv"> |
| 7 | <h2>Quickview</h2> |
| 8 | <ul> |
| 9 | <li> |
| 10 | Allow users to move data within your Activity layout using graphical gestures. |
| 11 | </li> |
| 12 | <li> |
| 13 | Supports operations besides data movement. |
| 14 | </li> |
| 15 | <li> |
| 16 | Only works within a single application. |
| 17 | </li> |
| 18 | <li> |
| 19 | Requires API 11. |
| 20 | </li> |
| 21 | </ul> |
| 22 | <h2>In this document</h2> |
| 23 | <ol> |
| 24 | <li> |
| 25 | <a href="#AboutDragging">Overview</a> |
| 26 | <ol> |
| 27 | <li> |
| 28 | <a href="#DragDropLifecycle">The drag/drop process</a> |
| 29 | </li> |
| 30 | <li> |
| 31 | <a href="#AboutDragListeners">The drag event listener and callback method</a> |
| 32 | </li> |
| 33 | <li> |
| 34 | <a href="#AboutDragEvent">Drag events</a> |
| 35 | </li> |
| 36 | <li> |
| 37 | <a href="#AboutDragShadowBuilder"> |
| 38 | The drag shadow</a> |
| 39 | </li> |
| 40 | </ol> |
| 41 | </li> |
| 42 | <li> |
| 43 | <a href="#DesignDragOperation">Designing a Drag and Drop Operation</a> |
| 44 | <ol> |
| 45 | <li> |
| 46 | <a href="#StartDrag">Starting a drag</a> |
| 47 | </li> |
| 48 | <li> |
| 49 | <a href="#HandleStart">Responding to a drag start</a> |
| 50 | </li> |
| 51 | <li> |
| 52 | <a href="#HandleDuring">Handling events during the drag</a> |
| 53 | </li> |
| 54 | <li> |
| 55 | <a href="#HandleDrop">Responding to a drop</a> |
| 56 | </li> |
| 57 | <li> |
| 58 | <a href="#HandleEnd">Responding to a drag end</a> |
| 59 | </li> |
| 60 | <li> |
| 61 | <a href="#RespondEventSample">Responding to drag events: an example</a> |
| 62 | </li> |
| 63 | </ol> |
| 64 | </li> |
| 65 | </ol> |
| 66 | <h2>Key classes</h2> |
| 67 | <ol> |
| 68 | <li> |
| 69 | {@link android.view.View View} |
| 70 | </li> |
| 71 | <li> |
| 72 | {@link android.view.View.OnLongClickListener OnLongClickListener} |
| 73 | </li> |
| 74 | <li> |
| 75 | {@link android.view.View.OnDragListener OnDragListener} |
| 76 | </li> |
| 77 | <li> |
| 78 | {@link android.view.DragEvent DragEvent} |
| 79 | </li> |
| 80 | <li> |
| 81 | {@link android.view.View.DragShadowBuilder DragShadowBuilder} |
| 82 | </li> |
| 83 | <li> |
| 84 | {@link android.content.ClipData ClipData} |
| 85 | </li> |
| 86 | <li> |
| 87 | {@link android.content.ClipDescription ClipDescription} |
| 88 | </li> |
| 89 | </ol> |
| 90 | <h2>Related Samples</h2> |
| 91 | <ol> |
| 92 | <li> |
Scott Main | 64c7574 | 2011-02-14 14:38:24 -0800 | [diff] [blame] | 93 | <a href="{@docRoot}resources/samples/HoneycombGallery/index.html"> |
| 94 | Honeycomb Gallery</a>. |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 95 | </li> |
| 96 | <li> |
| 97 | <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/DragAndDropDemo.html"> |
| 98 | DragAndDropDemo.java</a> and |
| 99 | <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/DraggableDot.html"> |
| 100 | DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.html">Api Demos</a>. |
| 101 | </li> |
| 102 | </ol> |
| 103 | <h2>See also</h2> |
| 104 | <ol> |
| 105 | <li> |
| 106 | <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> |
| 107 | </li> |
| 108 | <li> |
Scott Main | b10b48f | 2011-09-13 16:40:52 -0700 | [diff] [blame] | 109 | <a href="{@docRoot}guide/topics/ui/ui-events.html">Input Events</a> |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 110 | </li> |
| 111 | </ol> |
| 112 | </div> |
| 113 | </div> |
| 114 | <p> |
| 115 | With the Android drag/drop framework, you can allow your users to move data |
| 116 | from one View to another View in the current layout using a graphical drag and drop gesture. |
| 117 | The framework includes a drag event class, drag listeners, and helper methods and classes. |
| 118 | </p> |
| 119 | <p> |
| 120 | Although the framework is primarily designed for data movement, you can use |
| 121 | it for other UI actions. For example, you could create an app that mixes colors when the user |
| 122 | drags a color icon over another icon. The rest of this topic, however, describes the |
| 123 | framework in terms of data movement. |
| 124 | </p> |
| 125 | <h2 id="AboutDragging">Overview</h2> |
| 126 | <p> |
| 127 | A drag and drop operation starts when the user makes some gesture that you recognize as a |
| 128 | signal to start dragging data. In response, your application tells the system that the drag is |
| 129 | starting. The system calls back to your application to get a representation of the data |
| 130 | being dragged. As the user's finger moves this representation (a "drag shadow") |
| 131 | over the current layout, the system sends drag events to the drag event listener objects and |
| 132 | drag event callback methods associated with the {@link android.view.View} objects in the layout. |
| 133 | Once the user releases the drag shadow, the system ends the drag operation. |
| 134 | </p> |
| 135 | <p> |
| 136 | You create a drag event listener object ("listeners") from a class that implements |
| 137 | {@link android.view.View.OnDragListener}. You set the drag event listener object for a View |
| 138 | with the View object's |
| 139 | {@link android.view.View#setOnDragListener(View.OnDragListener) setOnDragListener()} method. |
| 140 | Each View object also has a {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} |
| 141 | callback method. Both of these are described in more detail in the section |
| 142 | <a href="#AboutDragListeners">The drag event listener and callback method</a>. |
| 143 | </p> |
| 144 | <p class="note"> |
| 145 | <strong>Note</strong>: For the sake of simplicity, the following sections refer to the routine |
| 146 | that receives drag events as the "drag event listener", even though it may actually |
| 147 | be a callback method. |
| 148 | </p> |
| 149 | <p> |
| 150 | When you start a drag, you include both the data you are moving and metadata describing this |
| 151 | data as part of the call to the system. During the drag, the system sends drag events to the |
| 152 | drag event listeners or callback methods of each View in the layout. The listeners or callback |
| 153 | methods can use the metadata to decide if they want to accept the data when it is dropped. |
| 154 | If the user drops the data over a View object, and that View object's listener or callback |
| 155 | method has previously told the system that it wants to accept the drop, then the system sends |
| 156 | the data to the listener or callback method in a drag event. |
| 157 | </p> |
| 158 | <p> |
| 159 | Your application tells the system to start a drag by calling the |
| 160 | {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} |
| 161 | method. This tells the system to start sending drag events. The method also sends the data that |
| 162 | you are dragging. |
| 163 | </p> |
| 164 | <p> |
| 165 | You can call |
| 166 | {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} |
| 167 | for any attached View in the current layout. The system only uses the View object to get access |
| 168 | to global settings in your layout. |
| 169 | </p> |
| 170 | <p> |
| 171 | Once your application calls |
| 172 | {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}, |
| 173 | the rest of the process uses events that the system sends to the View objects in your current |
| 174 | layout. |
| 175 | </p> |
| 176 | <h3 id="DragDropLifecycle">The drag/drop process</h3> |
| 177 | <p> |
| 178 | There are basically four steps or states in the drag and drop process: |
| 179 | </p> |
| 180 | <dl> |
| 181 | <dt> |
| 182 | <em>Started</em> |
| 183 | </dt> |
| 184 | <dd> |
| 185 | In response to the user's gesture to begin a drag, your application calls |
| 186 | {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} |
| 187 | to tell the system to start a drag. The arguments |
| 188 | {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} |
| 189 | provide the data to be dragged, metadata for this data, and a callback for drawing the |
| 190 | drag shadow. |
| 191 | <p> |
| 192 | The system first responds by calling back to your application to get a drag shadow. It |
| 193 | then displays the drag shadow on the device. |
| 194 | </p> |
| 195 | <p> |
| 196 | Next, the system sends a drag event with action type |
| 197 | {@link android.view.DragEvent#ACTION_DRAG_STARTED} to the drag event listeners for |
| 198 | all the View objects in the current layout. To continue to receive drag events, |
| 199 | including a possible drop event, a drag event listener must return <code>true</code>. |
| 200 | This registers the listener with the system. Only registered listeners continue to |
| 201 | receive drag events. At this point, listeners can also change the appearance of their |
| 202 | View object to show that the listener can accept a drop event. |
| 203 | </p> |
| 204 | <p> |
| 205 | If the drag event listener returns <code>false</code>, then it will not receive drag |
| 206 | events for the current operation until the system sends a drag event with action type |
| 207 | {@link android.view.DragEvent#ACTION_DRAG_ENDED}. By sending <code>false</code>, the |
| 208 | listener tells the system that it is not interested in the drag operation and |
| 209 | does not want to accept the dragged data. |
| 210 | </p> |
| 211 | </dd> |
| 212 | <dt> |
| 213 | <em>Continuing</em> |
| 214 | </dt> |
| 215 | <dd> |
| 216 | The user continues the drag. As the drag shadow intersects the bounding box of a View |
| 217 | object, the system sends one or more drag events to the View object's drag event |
| 218 | listener (if it is registered to receive events). The listener may choose to |
| 219 | alter its View object's appearance in response to the event. For example, if the event |
| 220 | indicates that the drag shadow has entered the bounding box of the View |
| 221 | (action type {@link android.view.DragEvent#ACTION_DRAG_ENTERED}), the listener |
| 222 | can react by highlighting its View. |
| 223 | </dd> |
| 224 | <dt> |
| 225 | <em>Dropped</em> |
| 226 | </dt> |
| 227 | <dd> |
| 228 | The user releases the drag shadow within the bounding box of a View that can accept the |
| 229 | data. The system sends the View object's listener a drag event with action type |
| 230 | {@link android.view.DragEvent#ACTION_DROP}. The drag event contains the data that was |
| 231 | passed to the system in the call to |
| 232 | {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} |
| 233 | that started the operation. The listener is expected to return boolean <code>true</code> to |
| 234 | the system if code for accepting the drop succeeds. |
| 235 | <p> |
| 236 | Note that this step only occurs if the user drops the drag shadow within the bounding |
| 237 | box of a View whose listener is registered to receive drag events. If the user releases |
| 238 | the drag shadow in any other situation, no {@link android.view.DragEvent#ACTION_DROP} |
| 239 | drag event is sent. |
| 240 | </p> |
| 241 | </dd> |
| 242 | <dt> |
| 243 | <em>Ended</em> |
| 244 | </dt> |
| 245 | <dd> |
| 246 | After the user releases the drag shadow, and after the system sends out (if necessary) |
| 247 | a drag event with action type {@link android.view.DragEvent#ACTION_DROP}, the system sends |
| 248 | out a drag event with action type {@link android.view.DragEvent#ACTION_DRAG_ENDED} to |
| 249 | indicate that the drag operation is over. This is done regardless of where the user released |
| 250 | the drag shadow. The event is sent to every listener that is registered to receive drag |
| 251 | events, even if the listener received the {@link android.view.DragEvent#ACTION_DROP} event. |
| 252 | </dd> |
| 253 | </dl> |
| 254 | <p> |
| 255 | Each of these four steps is described in more detail in the section |
| 256 | <a href="#DesignDragOperation">Designing a Drag and Drop Operation</a>. |
| 257 | </p> |
| 258 | <h3 id="AboutDragListeners">The drag event listener and callback method</h3> |
| 259 | <p> |
| 260 | A View receives drag events with either a drag event listener that implements |
| 261 | {@link android.view.View.OnDragListener} or with its |
| 262 | {@link android.view.View#onDragEvent(DragEvent)} callback method. |
| 263 | When the system calls the method or listener, it passes to them |
| 264 | a {@link android.view.DragEvent} object. |
| 265 | </p> |
| 266 | <p> |
| 267 | You will probably want to use the listener in most cases. When you design UIs, you usually |
| 268 | don't subclass View classes, but using the callback method forces you to do this in order to |
| 269 | override the method. In comparison, you can implement one listener class and then use it with |
| 270 | several different View objects. You can also implement it as an anonymous inline class. To |
| 271 | set the listener for a View object, call |
| 272 | {@link android.view.View#setOnDragListener(android.view.View.OnDragListener) setOnDragListener()}. |
| 273 | </p> |
| 274 | <p> |
| 275 | You can have both a listener and a callback method for View object. If this occurs, |
| 276 | the system first calls the listener. The system doesn't call the callback method unless the |
| 277 | listener returns <code>false</code>. |
| 278 | </p> |
| 279 | <p> |
| 280 | The combination of the {@link android.view.View#onDragEvent(DragEvent)} method and |
| 281 | {@link android.view.View.OnDragListener} is analogous to the combination |
| 282 | of the {@link android.view.View#onTouchEvent(MotionEvent) onTouchEvent()} and |
| 283 | {@link android.view.View.OnTouchListener} used with touch events. |
| 284 | </p> |
| 285 | <h3 id="AboutDragEvent">Drag events</h3> |
| 286 | <p> |
| 287 | The system sends out a drag event in the form of a {@link android.view.DragEvent} object. The |
| 288 | object contains an action type that tells the listener what is happening in the drag/drop |
| 289 | process. The object contains other data, depending on the action type. |
| 290 | </p> |
| 291 | <p> |
| 292 | To get the action type, a listener calls {@link android.view.DragEvent#getAction()}. There |
| 293 | are six possible values, defined by constants in the {@link android.view.DragEvent} class. These |
Scott Main | 13033ea | 2011-02-15 13:18:30 -0800 | [diff] [blame] | 294 | are listed in <a href="#table1">table 1</a>. |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 295 | </p> |
| 296 | <p> |
| 297 | The {@link android.view.DragEvent} object also contains the data that your application provided |
| 298 | to the system in the call to |
| 299 | {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}. |
| 300 | Some of the data is valid only for certain action types. The data that is valid for each action |
Scott Main | 13033ea | 2011-02-15 13:18:30 -0800 | [diff] [blame] | 301 | type is summarized in <a href="#table2">table 2</a>. It is also described in detail with |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 302 | the event for which it is valid in the section |
| 303 | <a href="#DesignDragOperation">Designing a Drag and Drop Operation</a>. |
| 304 | </p> |
| 305 | <p class="table-caption" id="table1"> |
| 306 | <strong>Table 1.</strong> DragEvent action types |
| 307 | </p> |
| 308 | <table> |
| 309 | <tr> |
| 310 | <th scope="col">getAction() value</th> |
| 311 | <th scope="col">Meaning</th> |
| 312 | </tr> |
| 313 | <tr> |
| 314 | <td>{@link android.view.DragEvent#ACTION_DRAG_STARTED}</td> |
| 315 | <td> |
| 316 | A View object's drag event listener receives this event action type just after the |
| 317 | application calls |
| 318 | {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} and |
| 319 | gets a drag shadow. |
| 320 | </td> |
| 321 | </tr> |
| 322 | <tr> |
| 323 | <td>{@link android.view.DragEvent#ACTION_DRAG_ENTERED}</td> |
| 324 | <td> |
| 325 | A View object's drag event listener receives this event action type when the drag shadow |
| 326 | has just entered the bounding box of the View. This is the first event action type the |
| 327 | listener receives when the drag shadow enters the bounding box. If the listener wants to |
| 328 | continue receiving drag events for this operation, it must return boolean |
| 329 | <code>true</code> to the system. |
| 330 | </td> |
| 331 | </tr> |
| 332 | <tr> |
| 333 | <td>{@link android.view.DragEvent#ACTION_DRAG_LOCATION}</td> |
| 334 | <td> |
| 335 | A View object's drag event listener receives this event action type after it receives a |
| 336 | {@link android.view.DragEvent#ACTION_DRAG_ENTERED} event while the drag shadow is |
| 337 | still within the bounding box of the View. |
| 338 | </td> |
| 339 | </tr> |
| 340 | <tr> |
| 341 | <td>{@link android.view.DragEvent#ACTION_DRAG_EXITED}</td> |
| 342 | <td> |
| 343 | A View object's drag event listener receives this event action type after it receives a |
| 344 | {@link android.view.DragEvent#ACTION_DRAG_ENTERED} and at least one |
| 345 | {@link android.view.DragEvent#ACTION_DRAG_LOCATION} event, and after the user has moved |
| 346 | the drag shadow outside the bounding box of the View. |
| 347 | </td> |
| 348 | </tr> |
| 349 | <tr> |
| 350 | <td>{@link android.view.DragEvent#ACTION_DROP}</td> |
| 351 | <td> |
| 352 | A View object's drag event listener receives this event action type when the user |
| 353 | releases the drag shadow over the View object. This action type is only sent to a View |
| 354 | object's listener if the listener returned boolean <code>true</code> in response to the |
| 355 | {@link android.view.DragEvent#ACTION_DRAG_STARTED} drag event. This action type is not |
| 356 | sent if the user releases the drag shadow on a View whose listener is not registered, |
| 357 | or if the user releases the drag shadow on anything that is not part of the current |
| 358 | layout. |
| 359 | <p> |
| 360 | The listener is expected to return boolean <code>true</code> if it successfully |
| 361 | processes the drop. Otherwise, it should return <code>false</code>. |
| 362 | </p> |
| 363 | </td> |
| 364 | </tr> |
| 365 | <tr> |
| 366 | <td>{@link android.view.DragEvent#ACTION_DRAG_ENDED}</td> |
| 367 | <td> |
| 368 | A View object's drag event listener receives this event action type |
| 369 | when the system is ending the drag operation. This action type is not necessarily |
| 370 | preceded by an {@link android.view.DragEvent#ACTION_DROP} event. If the system sent |
| 371 | a {@link android.view.DragEvent#ACTION_DROP}, receiving the |
| 372 | {@link android.view.DragEvent#ACTION_DRAG_ENDED} action type does not imply that the |
| 373 | drop operation succeeded. The listener must call |
| 374 | {@link android.view.DragEvent#getResult()} to get the value that was |
| 375 | returned in response to {@link android.view.DragEvent#ACTION_DROP}. If an |
| 376 | {@link android.view.DragEvent#ACTION_DROP} event was not sent, then |
| 377 | {@link android.view.DragEvent#getResult()} returns <code>false</code>. |
| 378 | </td> |
| 379 | </tr> |
| 380 | </table> |
| 381 | <p class="table-caption" id="table2"> |
| 382 | <strong>Table 2.</strong> Valid DragEvent data by action type</p> |
| 383 | <table> |
| 384 | <tr> |
| 385 | <th scope="col">{@link android.view.DragEvent#getAction()} value</th> |
| 386 | <th scope="col">{@link android.view.DragEvent#getClipDescription()} value</th> |
| 387 | <th scope="col">{@link android.view.DragEvent#getLocalState()} value</th> |
| 388 | <th scope="col">{@link android.view.DragEvent#getX()} value</th> |
| 389 | <th scope="col">{@link android.view.DragEvent#getY()} value</th> |
| 390 | <th scope="col">{@link android.view.DragEvent#getClipData()} value</th> |
| 391 | <th scope="col">{@link android.view.DragEvent#getResult()} value</th> |
| 392 | </tr> |
| 393 | <tr> |
| 394 | <td>{@link android.view.DragEvent#ACTION_DRAG_STARTED}</td> |
| 395 | <td style="text-align: center;">X</td> |
| 396 | <td style="text-align: center;">X</td> |
| 397 | <td style="text-align: center;">X</td> |
| 398 | <td style="text-align: center;"> </td> |
| 399 | <td style="text-align: center;"> </td> |
| 400 | <td style="text-align: center;"> </td> |
| 401 | </tr> |
| 402 | <tr> |
| 403 | <td>{@link android.view.DragEvent#ACTION_DRAG_ENTERED}</td> |
| 404 | <td style="text-align: center;">X</td> |
| 405 | <td style="text-align: center;">X</td> |
| 406 | <td style="text-align: center;">X</td> |
| 407 | <td style="text-align: center;">X</td> |
| 408 | <td style="text-align: center;"> </td> |
| 409 | <td style="text-align: center;"> </td> |
| 410 | </tr> |
| 411 | <tr> |
| 412 | <td>{@link android.view.DragEvent#ACTION_DRAG_LOCATION}</td> |
| 413 | <td style="text-align: center;">X</td> |
| 414 | <td style="text-align: center;">X</td> |
| 415 | <td style="text-align: center;">X</td> |
| 416 | <td style="text-align: center;">X</td> |
| 417 | <td style="text-align: center;"> </td> |
| 418 | <td style="text-align: center;"> </td> |
| 419 | </tr> |
| 420 | <tr> |
| 421 | <td>{@link android.view.DragEvent#ACTION_DRAG_EXITED}</td> |
| 422 | <td style="text-align: center;">X</td> |
| 423 | <td style="text-align: center;">X</td> |
| 424 | <td style="text-align: center;"> </td> |
| 425 | <td style="text-align: center;"> </td> |
| 426 | <td style="text-align: center;"> </td> |
| 427 | <td style="text-align: center;"> </td> |
| 428 | </tr> |
| 429 | <tr> |
| 430 | <td>{@link android.view.DragEvent#ACTION_DROP}</td> |
| 431 | <td style="text-align: center;">X</td> |
| 432 | <td style="text-align: center;">X</td> |
| 433 | <td style="text-align: center;">X</td> |
| 434 | <td style="text-align: center;">X</td> |
| 435 | <td style="text-align: center;">X</td> |
| 436 | <td style="text-align: center;"> </td> |
| 437 | </tr> |
| 438 | <tr> |
| 439 | <td>{@link android.view.DragEvent#ACTION_DRAG_ENDED}</td> |
| 440 | <td style="text-align: center;">X</td> |
| 441 | <td style="text-align: center;">X</td> |
| 442 | <td style="text-align: center;"> </td> |
| 443 | <td style="text-align: center;"> </td> |
| 444 | <td style="text-align: center;"> </td> |
| 445 | <td style="text-align: center;">X</td> |
| 446 | </tr> |
| 447 | </table> |
| 448 | <p> |
| 449 | The {@link android.view.DragEvent#getAction()}, |
| 450 | {@link android.view.DragEvent#describeContents()}, |
| 451 | {@link android.view.DragEvent#writeToParcel(Parcel,int) writeToParcel()}, and |
| 452 | {@link android.view.DragEvent#toString()} methods always return valid data. |
| 453 | </p> |
| 454 | <p> |
| 455 | If a method does not contain valid data for a particular action type, it returns either |
| 456 | <code>null</code> or 0, depending on its result type. |
| 457 | </p> |
| 458 | <h3 id="AboutDragShadowBuilder"> |
| 459 | The drag shadow |
| 460 | </h3> |
| 461 | <p> |
| 462 | During a drag and drop operation, the system displays a image that the user drags. |
| 463 | For data movement, this image represents the data being dragged. For other operations, the |
| 464 | image represents some aspect of the drag operation. |
| 465 | </p> |
| 466 | <p> |
| 467 | The image is called a drag shadow. You create it with methods you declare for a |
| 468 | {@link android.view.View.DragShadowBuilder} object, and then pass it to the system when you |
| 469 | start a drag using |
| 470 | {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}. |
| 471 | As part of its response to |
| 472 | {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}, |
| 473 | the system invokes the callback methods you've defined in |
| 474 | {@link android.view.View.DragShadowBuilder} to obtain a drag shadow. |
| 475 | </p> |
| 476 | <p> |
| 477 | The {@link android.view.View.DragShadowBuilder} class has two constructors: |
| 478 | </p> |
| 479 | <dl> |
| 480 | <dt>{@link android.view.View.DragShadowBuilder#View.DragShadowBuilder(View)}</dt> |
| 481 | <dd> |
| 482 | This constructor accepts any of your application's |
| 483 | {@link android.view.View} objects. The constructor stores the View object |
| 484 | in the {@link android.view.View.DragShadowBuilder} object, so during |
| 485 | the callback you can access it as you construct your drag shadow. |
| 486 | It doesn't have to be associated with the View (if any) that the user |
| 487 | selected to start the drag operation. |
| 488 | <p> |
| 489 | If you use this constructor, you don't have to extend |
| 490 | {@link android.view.View.DragShadowBuilder} or override its methods. By default, |
| 491 | you will get a drag shadow that has the same appearance as the View you pass as an |
| 492 | argument, centered under the location where the user is touching the screen. |
| 493 | </p> |
| 494 | </dd> |
| 495 | <dt>{@link android.view.View.DragShadowBuilder#View.DragShadowBuilder()}</dt> |
| 496 | <dd> |
| 497 | If you use this constructor, no View object is available in the |
| 498 | {@link android.view.View.DragShadowBuilder} object (the field is set to <code>null</code>). |
| 499 | If you use this constructor, and you don't extend |
| 500 | {@link android.view.View.DragShadowBuilder} or override its methods, |
| 501 | you will get an invisible drag shadow. |
| 502 | The system does <em>not</em> give an error. |
| 503 | </dd> |
| 504 | </dl> |
| 505 | <p> |
| 506 | The {@link android.view.View.DragShadowBuilder} class has two methods: |
| 507 | </p> |
| 508 | <dl> |
| 509 | <dt> |
| 510 | {@link android.view.View.DragShadowBuilder#onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} |
| 511 | </dt> |
| 512 | <dd> |
| 513 | The system calls this method immediately after you call |
| 514 | {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}. Use it |
| 515 | to send to the system the dimensions and touch point of the drag shadow. The method has two |
| 516 | arguments: |
| 517 | <dl> |
| 518 | <dt><em>dimensions</em></dt> |
| 519 | <dd> |
| 520 | A {@link android.graphics.Point} object. The drag shadow width goes in |
| 521 | {@link android.graphics.Point#x} and its height goes in |
| 522 | {@link android.graphics.Point#y}. |
| 523 | </dd> |
| 524 | <dt><em>touch_point</em></dt> |
| 525 | <dd> |
| 526 | A {@link android.graphics.Point} object. The touch point is the location within the |
| 527 | drag shadow that should be under the user's finger during the drag. Its X |
| 528 | position goes in {@link android.graphics.Point#x} and its Y position goes in |
| 529 | {@link android.graphics.Point#y} |
| 530 | </dd> |
| 531 | </dl> |
| 532 | </dd> |
| 533 | <dt> |
| 534 | {@link android.view.View.DragShadowBuilder#onDrawShadow(Canvas) onDrawShadow()} |
| 535 | </dt> |
| 536 | <dd> |
| 537 | Immediately after the call to |
| 538 | {@link android.view.View.DragShadowBuilder#onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} |
| 539 | the system calls |
| 540 | {@link android.view.View.DragShadowBuilder#onDrawShadow(Canvas) onDrawShadow()} to get the |
| 541 | drag shadow itself. The method has a single argument, a {@link android.graphics.Canvas} |
| 542 | object that the system constructs from the parameters you provide in |
| 543 | {@link android.view.View.DragShadowBuilder#onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} |
| 544 | Use it to draw the drag shadow in the provided {@link android.graphics.Canvas} object. |
| 545 | </dd> |
| 546 | </dl> |
| 547 | <p> |
| 548 | To improve performance, you should keep the size of the drag shadow small. For a single item, |
| 549 | you may want to use a icon. For a multiple selection, you may want to use icons in a stack |
| 550 | rather than full images spread out over the screen. |
| 551 | </p> |
| 552 | <h2 id="DesignDragOperation">Designing a Drag and Drop Operation</h2> |
| 553 | <p> |
| 554 | This section shows step-by-step how to start a drag, how to respond to events during |
| 555 | the drag, how respond to a drop event, and how to end the drag and drop operation. |
| 556 | </p> |
| 557 | <h3 id="StartDrag">Starting a drag</h3> |
| 558 | <p> |
| 559 | The user starts a drag with a drag gesture, usually a long press, on a View object. |
| 560 | In response, you should do the following: |
| 561 | </p> |
| 562 | <ol> |
| 563 | <li> |
| 564 | As necessary, create a {@link android.content.ClipData} and |
| 565 | {@link android.content.ClipData.Item} for the data being moved. As part of the |
| 566 | ClipData object, supply metadata that is stored in a {@link android.content.ClipDescription} |
| 567 | object within the ClipData. For a drag and drop operation that does not represent data |
| 568 | movement, you may want to use <code>null</code> instead of an actual object. |
| 569 | <p> |
| 570 | For example, this code snippet shows how to respond to a long press on a ImageView |
| 571 | by creating a ClipData object that contains the tag or label of an |
| 572 | ImageView. Following this snippet, the next snippet shows how to override the methods in |
| 573 | {@link android.view.View.DragShadowBuilder}: |
| 574 | </p> |
| 575 | <pre> |
| 576 | // Create a string for the ImageView label |
| 577 | private static final String IMAGEVIEW_TAG = "icon bitmap" |
| 578 | |
| 579 | // Creates a new ImageView |
| 580 | ImageView imageView = new ImageView(this); |
| 581 | |
| 582 | // Sets the bitmap for the ImageView from an icon bit map (defined elsewhere) |
| 583 | imageView.setImageBitmap(mIconBitmap); |
| 584 | |
| 585 | // Sets the tag |
| 586 | imageView.setTag(IMAGEVIEW_TAG); |
| 587 | |
| 588 | ... |
| 589 | |
| 590 | // Sets a long click listener for the ImageView using an anonymous listener object that |
| 591 | // implements the OnLongClickListener interface |
| 592 | imageView.setOnLongClickListener(new View.OnLongClickListener() { |
| 593 | |
| 594 | // Defines the one method for the interface, which is called when the View is long-clicked |
| 595 | public boolean onLongClick(View v) { |
| 596 | |
| 597 | // Create a new ClipData. |
| 598 | // This is done in two steps to provide clarity. The convenience method |
| 599 | // ClipData.newPlainText() can create a plain text ClipData in one step. |
| 600 | |
| 601 | // Create a new ClipData.Item from the ImageView object's tag |
| 602 | ClipData.Item item = new ClipData.Item(v.getTag()); |
| 603 | |
| 604 | // Create a new ClipData using the tag as a label, the plain text MIME type, and |
| 605 | // the already-created item. This will create a new ClipDescription object within the |
| 606 | // ClipData, and set its MIME type entry to "text/plain" |
| 607 | ClipData dragData = new ClipData(v.getTag(),ClipData.MIMETYPE_TEXT_PLAIN,item); |
| 608 | |
| 609 | // Instantiates the drag shadow builder. |
Joe Malin | 67970e8 | 2012-07-03 13:54:29 -0700 | [diff] [blame] | 610 | View.DragShadowBuilder myShadow = new MyDragShadowBuilder(imageView); |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 611 | |
| 612 | // Starts the drag |
| 613 | |
| 614 | v.startDrag(dragData, // the data to be dragged |
| 615 | myShadow, // the drag shadow builder |
| 616 | null, // no need to use local data |
| 617 | 0 // flags (not currently used, set to 0) |
| 618 | ); |
| 619 | |
| 620 | } |
| 621 | } |
| 622 | </pre> |
| 623 | </li> |
| 624 | <li> |
| 625 | The following code snippet defines {@code myDragShadowBuilder} |
| 626 | It creates a drag shadow for dragging a TextView as a small gray rectangle: |
| 627 | <pre> |
| 628 | private static class MyDragShadowBuilder extends View.DragShadowBuilder { |
| 629 | |
| 630 | // The drag shadow image, defined as a drawable thing |
| 631 | private static Drawable shadow; |
| 632 | |
| 633 | // Defines the constructor for myDragShadowBuilder |
| 634 | public MyDragShadowBuilder(View v) { |
| 635 | |
| 636 | // Stores the View parameter passed to myDragShadowBuilder. |
| 637 | super(v); |
| 638 | |
| 639 | // Creates a draggable image that will fill the Canvas provided by the system. |
| 640 | shadow = new ColorDrawable(Color.LTGRAY); |
| 641 | } |
| 642 | |
| 643 | // Defines a callback that sends the drag shadow dimensions and touch point back to the |
| 644 | // system. |
| 645 | @Override |
| 646 | public void onProvideShadowMetrics (Point size, Point touch) |
| 647 | // Defines local variables |
| 648 | private int width, height; |
| 649 | |
| 650 | // Sets the width of the shadow to half the width of the original View |
| 651 | width = getView().getWidth() / 2; |
| 652 | |
| 653 | // Sets the height of the shadow to half the height of the original View |
| 654 | height = getView().getHeight() / 2; |
| 655 | |
| 656 | // The drag shadow is a ColorDrawable. This sets its dimensions to be the same as the |
| 657 | // Canvas that the system will provide. As a result, the drag shadow will fill the |
| 658 | // Canvas. |
| 659 | shadow.setBounds(0, 0, width, height); |
| 660 | |
| 661 | // Sets the size parameter's width and height values. These get back to the system |
| 662 | // through the size parameter. |
| 663 | size.set(width, height); |
| 664 | |
| 665 | // Sets the touch point's position to be in the middle of the drag shadow |
| 666 | touch.set(width / 2, height / 2); |
| 667 | } |
| 668 | |
| 669 | // Defines a callback that draws the drag shadow in a Canvas that the system constructs |
| 670 | // from the dimensions passed in onProvideShadowMetrics(). |
| 671 | @Override |
| 672 | public void onDrawShadow(Canvas canvas) { |
| 673 | |
| 674 | // Draws the ColorDrawable in the Canvas passed in from the system. |
| 675 | shadow.draw(canvas); |
| 676 | } |
| 677 | } |
| 678 | </pre> |
| 679 | <p class="note"> |
| 680 | <strong>Note:</strong> Remember that you don't have to extend |
| 681 | {@link android.view.View.DragShadowBuilder}. The constructor |
| 682 | {@link android.view.View.DragShadowBuilder#View.DragShadowBuilder(View)} creates a |
| 683 | default drag shadow that's the same size as the View argument passed to it, with the |
| 684 | touch point centered in the drag shadow. |
| 685 | </p> |
| 686 | </li> |
| 687 | </ol> |
| 688 | <h3 id="HandleStart">Responding to a drag start</h3> |
| 689 | <p> |
| 690 | During the drag operation, the system dispatches drag events to the drag event listeners |
| 691 | of the View objects in the current layout. The listeners should react |
| 692 | by calling {@link android.view.DragEvent#getAction()} to get the action type. |
| 693 | At the start of a drag, this methods returns {@link android.view.DragEvent#ACTION_DRAG_STARTED}. |
| 694 | </p> |
| 695 | <p> |
| 696 | In response to an event with the action type {@link android.view.DragEvent#ACTION_DRAG_STARTED}, |
| 697 | a listener should do the following: |
| 698 | </p> |
| 699 | <ol> |
| 700 | <li> |
| 701 | Call {@link android.view.DragEvent#getClipDescription()} to get the |
| 702 | {@link android.content.ClipDescription}. Use the MIME type methods in |
| 703 | {@link android.content.ClipDescription} to see if the listener can accept the data being |
| 704 | dragged. |
| 705 | <p> |
| 706 | If the drag and drop operation does not represent data movement, this may not be |
| 707 | necessary. |
| 708 | </p> |
| 709 | </li> |
| 710 | <li> |
| 711 | If the listener can accept a drop, it should return <code>true</code>. This tells |
| 712 | the system to continue to send drag events to the listener. |
| 713 | If it can't accept a drop, it should return <code>false</code>, and the system |
| 714 | will stop sending drag events until it sends out |
| 715 | {@link android.view.DragEvent#ACTION_DRAG_ENDED}. |
| 716 | </li> |
| 717 | </ol> |
| 718 | <p> |
| 719 | Note that for an {@link android.view.DragEvent#ACTION_DRAG_STARTED} event, these |
| 720 | the following {@link android.view.DragEvent} methods are not valid: |
| 721 | {@link android.view.DragEvent#getClipData()}, {@link android.view.DragEvent#getX()}, |
| 722 | {@link android.view.DragEvent#getY()}, and {@link android.view.DragEvent#getResult()}. |
| 723 | </p> |
| 724 | <h3 id="HandleDuring">Handling events during the drag</h3> |
| 725 | <p> |
| 726 | During the drag, listeners that returned <code>true</code> in response to |
| 727 | the {@link android.view.DragEvent#ACTION_DRAG_STARTED} drag event continue to receive drag |
| 728 | events. The types of drag events a listener receives during the drag depend on the location of |
| 729 | the drag shadow and the visibility of the listener's View. |
| 730 | </p> |
| 731 | <p> |
| 732 | During the drag, listeners primarily use drag events to decide if they should change the |
| 733 | appearance of their View. |
| 734 | </p> |
| 735 | <p> |
| 736 | During the drag, {@link android.view.DragEvent#getAction()} returns one of three |
| 737 | values: |
| 738 | </p> |
| 739 | <ul> |
| 740 | <li> |
| 741 | {@link android.view.DragEvent#ACTION_DRAG_ENTERED}: |
| 742 | The listener receives this when the touch point |
| 743 | (the point on the screen underneath the user's finger) has entered the bounding box of the |
| 744 | listener's View. |
| 745 | </li> |
| 746 | <li> |
| 747 | {@link android.view.DragEvent#ACTION_DRAG_LOCATION}: Once the listener receives an |
| 748 | {@link android.view.DragEvent#ACTION_DRAG_ENTERED} event, and before it receives an |
| 749 | A{@link android.view.DragEvent#ACTION_DRAG_EXITED} event, it receives a new |
| 750 | {@link android.view.DragEvent#ACTION_DRAG_LOCATION} event every time the touch point moves. |
| 751 | The {@link android.view.DragEvent#getX()} and {@link android.view.DragEvent#getY()} methods |
kmccormick | 76dfc02 | 2013-04-03 12:41:12 -0700 | [diff] [blame] | 752 | return the X and Y coordinates of the touch point. |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 753 | </li> |
| 754 | <li> |
| 755 | {@link android.view.DragEvent#ACTION_DRAG_EXITED}: This event is sent to a listener that |
| 756 | previously received {@link android.view.DragEvent#ACTION_DRAG_ENTERED}, after |
| 757 | the drag shadow is no longer within the bounding box of the listener's View. |
| 758 | </li> |
| 759 | </ul> |
| 760 | <p> |
| 761 | The listener does not need to react to any of these action types. If the listener returns a |
| 762 | value to the system, it is ignored. Here are some guidelines for responding to each of |
| 763 | these action types: |
| 764 | </p> |
| 765 | <ul> |
| 766 | <li> |
| 767 | In response to {@link android.view.DragEvent#ACTION_DRAG_ENTERED} or |
| 768 | {@link android.view.DragEvent#ACTION_DRAG_LOCATION}, the listener can change the appearance |
| 769 | of the View to indicate that it is about to receive a drop. |
| 770 | </li> |
| 771 | <li> |
| 772 | An event with the action type {@link android.view.DragEvent#ACTION_DRAG_LOCATION} contains |
| 773 | valid data for {@link android.view.DragEvent#getX()} and |
| 774 | {@link android.view.DragEvent#getY()}, corresponding to the location of the touch point. |
| 775 | The listener may want to use this information to alter the appearance of that part of the |
| 776 | View that is at the touch point. The listener can also use this information |
| 777 | to determine the exact position where the user is going to drop the drag shadow. |
| 778 | </li> |
| 779 | <li> |
| 780 | In response to {@link android.view.DragEvent#ACTION_DRAG_EXITED}, the listener should reset |
| 781 | any appearance changes it applied in response to |
| 782 | {@link android.view.DragEvent#ACTION_DRAG_ENTERED} or |
| 783 | {@link android.view.DragEvent#ACTION_DRAG_LOCATION}. This indicates to the user that |
| 784 | the View is no longer an imminent drop target. |
| 785 | </li> |
| 786 | </ul> |
| 787 | <h3 id="HandleDrop">Responding to a drop</h3> |
| 788 | <p> |
| 789 | When the user releases the drag shadow on a View in the application, and that View previously |
| 790 | reported that it could accept the content being dragged, the system dispatches a drag event |
| 791 | to that View with the action type {@link android.view.DragEvent#ACTION_DROP}. The listener |
| 792 | should do the following: |
| 793 | </p> |
| 794 | <ol> |
| 795 | <li> |
| 796 | Call {@link android.view.DragEvent#getClipData()} to get the |
| 797 | {@link android.content.ClipData} object that was originally supplied in the call |
| 798 | to |
| 799 | {@link android.view.View#startDrag(ClipData, View.DragShadowBuilder, Object, int) startDrag()} |
| 800 | and store it. If the drag and drop operation does not represent data movement, |
| 801 | this may not be necessary. |
| 802 | </li> |
| 803 | <li> |
| 804 | Return boolean <code>true</code> to indicate that the drop was processed successfully, or |
| 805 | boolean <code>false</code> if it was not. The returned value becomes the value returned by |
| 806 | {@link android.view.DragEvent#getResult()} for an |
| 807 | {@link android.view.DragEvent#ACTION_DRAG_ENDED} event. |
| 808 | <p> |
| 809 | Note that if the system does not send out an {@link android.view.DragEvent#ACTION_DROP} |
| 810 | event, the value of {@link android.view.DragEvent#getResult()} for an |
| 811 | {@link android.view.DragEvent#ACTION_DRAG_ENDED} event is <code>false</code>. |
| 812 | </p> |
| 813 | </li> |
| 814 | </ol> |
| 815 | <p> |
| 816 | For an {@link android.view.DragEvent#ACTION_DROP} event, |
| 817 | {@link android.view.DragEvent#getX()} and {@link android.view.DragEvent#getY()} |
| 818 | return the X and Y position of the drag point at the moment of the drop, using the coordinate |
| 819 | system of the View that received the drop. |
| 820 | </p> |
| 821 | <p> |
| 822 | The system does allow the user to release the drag shadow on a View whose listener is not |
| 823 | receiving drag events. It will also allow the user to release the drag shadow |
| 824 | on empty regions of the application's UI, or on areas outside of your application. |
| 825 | In all of these cases, the system does not send an event with action type |
| 826 | {@link android.view.DragEvent#ACTION_DROP}, although it does send out an |
| 827 | {@link android.view.DragEvent#ACTION_DRAG_ENDED} event. |
| 828 | </p> |
| 829 | <h3 id="HandleEnd">Responding to a drag end</h3> |
| 830 | <p> |
| 831 | Immediately after the user releases the drag shadow, the system sends a |
| 832 | drag event to all of the drag event listeners in your application, with an action type of |
| 833 | {@link android.view.DragEvent#ACTION_DRAG_ENDED}. This indicates that the drag operation is |
| 834 | over. |
| 835 | </p> |
| 836 | <p> |
| 837 | Each listener should do the following: |
| 838 | </p> |
| 839 | <ol> |
| 840 | <li> |
| 841 | If listener changed its View object's appearance during the operation, it should reset the |
| 842 | View to its default appearance. This is a visual indication to the user that the operation |
| 843 | is over. |
| 844 | </li> |
| 845 | <li> |
| 846 | The listener can optionally call {@link android.view.DragEvent#getResult()} to find out more |
| 847 | about the operation. If a listener returned <code>true</code> in response to an event of |
| 848 | action type {@link android.view.DragEvent#ACTION_DROP}, then |
| 849 | {@link android.view.DragEvent#getResult()} will return boolean <code>true</code>. In all |
| 850 | other cases, {@link android.view.DragEvent#getResult()} returns boolean <code>false</code>, |
| 851 | including any case in which the system did not send out a |
| 852 | {@link android.view.DragEvent#ACTION_DROP} event. |
| 853 | </li> |
| 854 | <li> |
| 855 | The listener should return boolean <code>true</code> to the system. |
| 856 | </li> |
| 857 | </ol> |
| 858 | <p> |
| 859 | </p> |
| 860 | <h3 id="RespondEventSample">Responding to drag events: an example</h3> |
| 861 | <p> |
| 862 | All drag events are initially received by your drag event method or listener. The following |
| 863 | code snippet is a simple example of reacting to drag events in a listener: |
| 864 | </p> |
| 865 | <pre> |
| 866 | // Creates a new drag event listener |
| 867 | mDragListen = new myDragEventListener(); |
| 868 | |
| 869 | View imageView = new ImageView(this); |
| 870 | |
| 871 | // Sets the drag event listener for the View |
| 872 | imageView.setOnDragListener(mDragListen); |
| 873 | |
| 874 | ... |
| 875 | |
Taeho Kim | 130e129 | 2013-10-17 10:43:06 +0900 | [diff] [blame] | 876 | protected class myDragEventListener implements View.OnDragListener { |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 877 | |
| 878 | // This is the method that the system calls when it dispatches a drag event to the |
| 879 | // listener. |
| 880 | public boolean onDrag(View v, DragEvent event) { |
| 881 | |
| 882 | // Defines a variable to store the action type for the incoming event |
| 883 | final int action = event.getAction(); |
| 884 | |
| 885 | // Handles each of the expected events |
| 886 | switch(action) { |
| 887 | |
| 888 | case DragEvent.ACTION_DRAG_STARTED: |
| 889 | |
| 890 | // Determines if this View can accept the dragged data |
| 891 | if (event.getClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) { |
| 892 | |
| 893 | // As an example of what your application might do, |
| 894 | // applies a blue color tint to the View to indicate that it can accept |
| 895 | // data. |
| 896 | v.setColorFilter(Color.BLUE); |
| 897 | |
| 898 | // Invalidate the view to force a redraw in the new tint |
| 899 | v.invalidate(); |
| 900 | |
| 901 | // returns true to indicate that the View can accept the dragged data. |
Taeho Kim | 67ab4ba | 2013-10-30 20:13:59 +0900 | [diff] [blame] | 902 | return true; |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 903 | |
Taeho Kim | 130e129 | 2013-10-17 10:43:06 +0900 | [diff] [blame] | 904 | } |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 905 | |
Taeho Kim | 130e129 | 2013-10-17 10:43:06 +0900 | [diff] [blame] | 906 | // Returns false. During the current drag and drop operation, this View will |
| 907 | // not receive events again until ACTION_DRAG_ENDED is sent. |
Taeho Kim | 67ab4ba | 2013-10-30 20:13:59 +0900 | [diff] [blame] | 908 | return false; |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 909 | |
Taeho Kim | 130e129 | 2013-10-17 10:43:06 +0900 | [diff] [blame] | 910 | case DragEvent.ACTION_DRAG_ENTERED: |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 911 | |
| 912 | // Applies a green tint to the View. Return true; the return value is ignored. |
| 913 | |
| 914 | v.setColorFilter(Color.GREEN); |
| 915 | |
| 916 | // Invalidate the view to force a redraw in the new tint |
| 917 | v.invalidate(); |
| 918 | |
Taeho Kim | 67ab4ba | 2013-10-30 20:13:59 +0900 | [diff] [blame] | 919 | return true; |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 920 | |
Taeho Kim | 130e129 | 2013-10-17 10:43:06 +0900 | [diff] [blame] | 921 | case DragEvent.ACTION_DRAG_LOCATION: |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 922 | |
| 923 | // Ignore the event |
Taeho Kim | 67ab4ba | 2013-10-30 20:13:59 +0900 | [diff] [blame] | 924 | return true; |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 925 | |
Taeho Kim | 130e129 | 2013-10-17 10:43:06 +0900 | [diff] [blame] | 926 | case DragEvent.ACTION_DRAG_EXITED: |
| 927 | |
| 928 | // Re-sets the color tint to blue. Returns true; the return value is ignored. |
| 929 | v.setColorFilter(Color.BLUE); |
| 930 | |
| 931 | // Invalidate the view to force a redraw in the new tint |
| 932 | v.invalidate(); |
| 933 | |
Taeho Kim | 67ab4ba | 2013-10-30 20:13:59 +0900 | [diff] [blame] | 934 | return true; |
Taeho Kim | 130e129 | 2013-10-17 10:43:06 +0900 | [diff] [blame] | 935 | |
| 936 | case DragEvent.ACTION_DROP: |
| 937 | |
| 938 | // Gets the item containing the dragged data |
| 939 | ClipData.Item item = event.getClipData().getItemAt(0); |
| 940 | |
| 941 | // Gets the text data from the item. |
| 942 | dragData = item.getText(); |
| 943 | |
| 944 | // Displays a message containing the dragged data. |
| 945 | Toast.makeText(this, "Dragged data is " + dragData, Toast.LENGTH_LONG); |
| 946 | |
| 947 | // Turns off any color tints |
| 948 | v.clearColorFilter(); |
| 949 | |
| 950 | // Invalidates the view to force a redraw |
| 951 | v.invalidate(); |
| 952 | |
| 953 | // Returns true. DragEvent.getResult() will return true. |
Taeho Kim | 67ab4ba | 2013-10-30 20:13:59 +0900 | [diff] [blame] | 954 | return true; |
Taeho Kim | 130e129 | 2013-10-17 10:43:06 +0900 | [diff] [blame] | 955 | |
| 956 | case DragEvent.ACTION_DRAG_ENDED: |
| 957 | |
| 958 | // Turns off any color tinting |
| 959 | v.clearColorFilter(); |
| 960 | |
| 961 | // Invalidates the view to force a redraw |
| 962 | v.invalidate(); |
| 963 | |
| 964 | // Does a getResult(), and displays what happened. |
| 965 | if (event.getResult()) { |
| 966 | Toast.makeText(this, "The drop was handled.", Toast.LENGTH_LONG); |
| 967 | |
| 968 | } else { |
| 969 | Toast.makeText(this, "The drop didn't work.", Toast.LENGTH_LONG); |
| 970 | |
| 971 | } |
| 972 | |
| 973 | // returns true; the value is ignored. |
Taeho Kim | 67ab4ba | 2013-10-30 20:13:59 +0900 | [diff] [blame] | 974 | return true; |
Taeho Kim | 130e129 | 2013-10-17 10:43:06 +0900 | [diff] [blame] | 975 | |
| 976 | // An unknown action type was received. |
| 977 | default: |
| 978 | Log.e("DragDrop Example","Unknown action type received by OnDragListener."); |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 979 | break; |
Taeho Kim | 130e129 | 2013-10-17 10:43:06 +0900 | [diff] [blame] | 980 | } |
| 981 | |
Taeho Kim | 67ab4ba | 2013-10-30 20:13:59 +0900 | [diff] [blame] | 982 | return false; |
Taeho Kim | 130e129 | 2013-10-17 10:43:06 +0900 | [diff] [blame] | 983 | } |
Joe Malin | dd05f18 | 2011-01-19 14:33:23 -0800 | [diff] [blame] | 984 | }; |
kmccormick | 76dfc02 | 2013-04-03 12:41:12 -0700 | [diff] [blame] | 985 | </pre> |