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