1 page.title=Drag and Drop 2 page.tags=clipdata,dragevent,onlongclicklistener 3 @jd:body 4 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> 93 <a href="{@docRoot}resources/samples/HoneycombGallery/index.html"> 94 Honeycomb Gallery</a>. 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> 109 <a href="{@docRoot}guide/topics/ui/ui-events.html">Input Events</a> 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 294 are listed in <a href="#table1">table 1</a>. 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 301 type is summarized in <a href="#table2">table 2</a>. It is also described in detail with 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. 610 View.DragShadowBuilder myShadow = new MyDragShadowBuilder(imageView); 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 752 return the X and Y coordinates of the touch point. 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 876 protected class myDragEventListener implements View.OnDragListener { 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. 902 return true; 903 904 } 905 906 // Returns false. During the current drag and drop operation, this View will 907 // not receive events again until ACTION_DRAG_ENDED is sent. 908 return false; 909 910 case DragEvent.ACTION_DRAG_ENTERED: 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 919 return true; 920 921 case DragEvent.ACTION_DRAG_LOCATION: 922 923 // Ignore the event 924 return true; 925 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 934 return true; 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. 954 return true; 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. 974 return true; 975 976 // An unknown action type was received. 977 default: 978 Log.e("DragDrop Example","Unknown action type received by OnDragListener."); 979 break; 980 } 981 982 return false; 983 } 984 }; 985 </pre> 986