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