1# Drag Event 2 3A drag event is triggered when a component is dragged. 4 5> **NOTE** 6> 7> This feature is supported since API version 7. Updates will be marked with a superscript to indicate their earliest API version. 8> 9> The resource files preset in the application (that is, the resource files that are contained in the HAP file before the application is installed) can be dragged and dropped only within the application. 10 11The ArkUI framework implements the drag and drop capability for the following components, allowing them to serve as the drag source (from which data can be dragged) or drop target (to which data can be dropped). To enable drag and drop for these components, you only need to set their [draggable](ts-universal-attributes-drag-drop.md) attribute to **true**. 12 13- The following component supports drag operations by default: **\<Search>**, **\<TextInput>**, **\<TextArea>**, **\<RichEditor>**, **\<Text>**, **\<Image>**, **\<FormComponent>**, **\<Hyperlink>** 14 15- The following component supports drop operations by default: **\<Search>**, **\<TextInput>**, **\<TextArea>**, **\<Video>** 16 17You can also define drag responses by implementing common drag events. 18 19To enable drag and drop for other components, you need to set the **draggable** attribute to **true** and implement data transmission in APIs such as **onDragStart**. 20 21## onDragStart 22 23onDragStart(event: (event: DragEvent, extraParams?: string) => CustomBuilder | DragItemInfo) 24 25Triggered when the component bound to the event is dragged for the first time. A drag operation is recognized only when the long press time is 500 ms or longer and the dragging distance is 10 vp or longer. 26 27**Event priority**:<br>Long press time < 500 ms: Long press event > Drag event<br>Other cases: Drag event > Long press event 28 29**System capability**: SystemCapability.ArkUI.ArkUI.Full 30 31**Parameters** 32 33| Name | Type | Mandatory| Description | 34| ----------- | ------------------------------- | ---- | ------------------ | 35| event | [DragEvent](#dragevent) | Yes | Information about the drag event. | 36| extraParams | [extraParams](#extraparams) | No | Additional information about the drag event.| 37 38**Return value** 39 40| Type | Description | 41| ------------------------------------------------------------ | ------------------------ | 42| [CustomBuilder](ts-types.md#custombuilder8) \| [DragItemInfo](#dragiteminfo) | Component information displayed during dragging.<br>**NOTE**<br>The global builder is not supported.| 43 44## onDragEnter 45 46onDragEnter(event: (event: DragEvent, extraParams?: string) => void) 47 48Triggered when the dragged item enters a valid drop target. This event is valid only when a listener for the [onDrop](#ondrop) event is enabled. 49 50**System capability**: SystemCapability.ArkUI.ArkUI.Full 51 52**Parameters** 53 54| Name | Type | Mandatory| Description | 55| ----------- | ------------------------------- | ---- | ------------------------------ | 56| event | [DragEvent](#dragevent) | Yes | Information about the drag event, including the coordinates of the item that is being dragged.| 57| extraParams | [extraParams](#extraparams) | No | Additional information about the drag event. | 58 59## onDragMove 60 61onDragMove(event: (event: DragEvent, extraParams?: string) => void) 62 63Triggered when the dragged item moves in a valid drop target. This event is valid only when a listener for the [onDrop](#ondrop) event is enabled. 64 65**System capability**: SystemCapability.ArkUI.ArkUI.Full 66 67**Parameters** 68 69| Name | Type | Mandatory| Description | 70| ----------- | ------------------------------- | ---- | ------------------------------ | 71| event | [DragEvent](#dragevent) | Yes | Information about the drag event, including the coordinates of the item that is being dragged.| 72| extraParams | [extraParams](#extraparams) | No | Additional information about the drag event. | 73 74## onDragLeave 75 76onDragLeave(event: (event: DragEvent, extraParams?: string) => void) 77 78Triggered when the dragged item leaves a valid drop target. This event is valid only when a listener for the [onDrop](#ondrop) event is enabled. 79 80**System capability**: SystemCapability.ArkUI.ArkUI.Full 81 82**Parameters** 83 84| Name | Type | Mandatory| Description | 85| ----------- | ------------------------------- | ---- | ------------------------------ | 86| event | [DragEvent](#dragevent) | Yes | Information about the drag event, including the coordinates of the item that is being dragged.| 87| extraParams | [extraParams](#extraparams) | No | Additional information about the drag event. | 88 89## onDrop 90 91onDrop(event: (event: DragEvent, extraParams?: string) => void) 92 93Triggered when the dragged item is dropped on a valid drop target. If **event.setResult()** is not explicitly used, the default value **DRAG_SUCCESSFUL** will be used as the result. 94 95**System capability**: SystemCapability.ArkUI.ArkUI.Full 96 97**Parameters** 98 99| Name | Type | Mandatory| Description | 100| ----------- | ------------------------------- | ---- | ------------------------------ | 101| event | [DragEvent](#dragevent) | Yes | Information about the drag event, including the coordinates of the item that is being dragged.| 102| extraParams | [extraParams](#extraparams) | No | Additional information about the drag event. | 103 104## onDragEnd 105 106onDragEnd(event: (event: DragEvent, extraParams?: string) => void) 107 108Triggered when the dragging of the component bound to the event ends. 109 110**System capability**: SystemCapability.ArkUI.ArkUI.Full 111 112**Parameters** 113 114| Name | Type | Mandatory| Description | 115| ----------- | ------------------------------- | ---- | ------------------------------ | 116| event | [DragEvent](#dragevent) | Yes | Information about the drag event, including the coordinates of the item that is being dragged.| 117| extraParams | [extraParams](#extraparams) | No | Additional information about the drag event. | 118 119## DragItemInfo 120 121| Name | Type | Mandatory | Description | 122| --------- | ---------------------------------------- | ---- | --------------------------------- | 123| pixelMap | [PixelMap](../apis/js-apis-image.md#pixelmap7) | No | Image to be displayed during dragging. | 124| builder | [CustomBuilder](ts-types.md#custombuilder8) | No | Custom component to display during dragging. If **pixelMap** is set, this attribute is ignored.<br> **NOTE**<br>Global builder definition is not supported. If the [\<Image>](../arkui-ts/ts-basic-components-image.md) component is used in the builder, enable synchronous loading, that is, set the [syncLoad](../arkui-ts/ts-basic-components-image.md#attributes) attribute of the component to **true**.| 125| extraInfo | string | No | Extra information of the dragged item. | 126 127 128## extraParams 129 130 Provides additional information required for dragging an item. 131 132 **extraParams** is a string converted from a JSON object. You can obtain the following attributes using the JSON object converted from **Json.parse**. 133 134| Name | Type | Description | 135| ------------- | ------ | ---------------------------------------- | 136| selectedIndex | number | Index of the dragged item in the parent container. The value of **selectedindex** starts from **0**.<br>This parameter is valid only in the drag event of the **\<ListItem>** component.| 137| insertIndex | number | Index of the element into which the dragged item is dropped in the **List** component. The value of **insertIndex** starts from **0**.<br>This parameter is valid only in the drag event of the **\<List>** component.| 138 139## DragEvent 140 141### Attributes 142 143| Name | Type | Description | 144| ------ | ------ | ---------------- | 145| useCustomDropAnimation<sup>10+</sup> | boolean | Whether to use the custom drop animation when the dragging ends.<br>If this parameter is set to **true**, the default drop animation is disabled, and the custom one is used.<br>If this parameter is set to **false** or is not set, the default drop animation is enabled. In this case, to avoid conflicts, the application should not implement any custom drop animation.| 146|dragBehavior<sup>10+</sup> | [DragBehavior](#dragbehavior10) | Copy or paste mode.| 147 148### Methods 149 150| Name | Return Value Type | Description | 151| ----------- | ------------------------------- | ------------------------------ | 152| setData(unifiedData: [UnifiedData](../apis/js-apis-data-unifiedDataChannel.md#unifieddata))<sup>10+</sup> | void | Sets drag-related data in the drag event.| 153| getData()<sup>10+</sup> | [UnifiedData](../apis/js-apis-data-unifiedDataChannel.md#unifieddata) | Obtains drag-related data from the drag event. For details about the data obtaining result, see the error code description.| 154| getSummary()<sup>10+</sup> | [Summary](../apis/js-apis-data-unifiedDataChannel.md#summary) | Obtains the summary of drag-related data from the drag event.| 155| setResult(dragRect: [DragResult](#dragresult10))<sup>10+</sup> | void | Sets the drag and drop result in the drag event.| 156| getResult()<sup>10+</sup> | [DragResult](#dragresult10) | Obtains the drag and drop result from the drag event.| 157| getPreviewRect()<sup>10+</sup> | [Rectangle](ts-universal-attributes-touch-target.md#rectangle) | Obtains the rectangle where the preview image is located.| 158| getVelocityX()<sup>10+</sup> | number | Obtains the dragging velocity along the x-axis. The origin of the coordinate axis is the upper left corner of the screen. The unit is vp. The velocity is positive if the movement is from left to right, and it is negative if the movement is from right to left.| 159| getVelocityY()<sup>10+</sup> | number | Obtains the dragging velocity along the y-axis. The origin of the coordinate axis is the upper left corner of the screen. The unit is vp. The velocity is positive if the movement is from top to bottom, and it is negative if the movement is from bottom to top.| 160| getVelocity()<sup>10+</sup> | number | Obtains the dragging velocity along the main axis. The value is the arithmetic square root of the sum of squares of the velocity along the x- and y-axis.| 161| getWindowX()<sup>10+</sup> | number | X coordinate of the drag position relative to the upper left corner of the window, in vp.| 162| getWindowY()<sup>10+</sup> | number | Y coordinate of the drag position relative to the upper left corner of the window, in vp.| 163| getDisplayX()<sup>10+</sup> | number | X coordinate of the drag position relative to the upper left corner of the screen, in vp.| 164| getDisplayY()<sup>10+</sup> | number | Y coordinate of the drag position relative to the upper left corner of the screen, in vp.| 165| getX()<sup>(deprecated)</sup> | number | X coordinate of the drag position relative to the upper left corner of the window, in vp.<br>This API is deprecated since API version 10. You are advised to use **getWindowX()** instead.| 166| getY()<sup>(deprecated)</sup> | number | Y coordinate of the drag position relative to the upper left corner of the window, in vp.<br>This API is deprecated since API version 10. You are advised to use **getWindowY()** instead.| 167 168 169**Error codes** 170 171For details about the error codes, see [Drag Event Error Codes](../errorcodes/errorcode-drag-event.md). 172 173| ID | Error Message| 174| --------- | ------- | 175| 190001 | GetData failed, data not found. | 176| 190002 | GetData failed, data error. | 177 178## DragResult<sup>10+</sup> 179 180| Name| Description| 181| ----- | ----------------- | 182| DRAG_SUCCESSFUL | The drag and drop operation succeeded. It can be used in **onDrop**.| 183| DRAG_FAILED | The drag and drop operation failed. It can be used in **onDrop**.| 184| DRAG_CANCELED | The drag and drop operation was canceled. It can be used in **onDrop**.| 185| DROP_ENABLED | The component allows for a drop operation. It can be used in **onDragMove**.| 186| DROP_DISABLED | The component does not allow for a drop operation. It can be used in **onDragMove**.| 187 188## DragBehavior<sup>10+</sup> 189 190Provides the drag behavior. This API takes effect only when [DragResult](#dragresult10) is set to **DROP_ENABLED** and the [onDrop](#ondrop) callback is implemented. 191 192| Name| Description| 193| ----- | ----------------- | 194| COPY | Copy mode.| 195| MOVE| Paste mode.| 196 197 198## Example 199 200```ts 201// xxx.ets 202import UDC from '@ohos.data.unifiedDataChannel'; 203import UTD from '@ohos.data.uniformTypeDescriptor'; 204import promptAction from '@ohos.promptAction'; 205import { BusinessError } from '@ohos.base'; 206 207@Entry 208@Component 209struct Index { 210 @State targetImage: string = ''; 211 @State targetText: string = 'Drag Text'; 212 @State imageWidth: number = 100; 213 @State imageHeight: number = 100; 214 @State imgState: Visibility = Visibility.Visible; 215 @State videoSrc: string = 'resource://RAWFILE/02.mp4'; 216 @State abstractContent: string = "abstract"; 217 @State textContent: string = ""; 218 219 @Builder 220 pixelMapBuilder() { 221 Column() { 222 Image($r('app.media.icon')) 223 .width(120) 224 .height(120) 225 .backgroundColor(Color.Yellow) 226 } 227 } 228 229 getDataFromUdmfRetry(event: DragEvent, callback: (data: DragEvent) => void) { 230 try { 231 let data: UnifiedData = event.getData(); 232 if (!data) { 233 return false; 234 } 235 let records: Array<UDC.UnifiedRecord> = data.getRecords(); 236 if (!records || records.length <= 0) { 237 return false; 238 } 239 callback(event); 240 return true; 241 } catch (e) { 242 console.log("getData failed, code = " + (e as BusinessError).code + ", message = " + (e as BusinessError).message); 243 return false; 244 } 245 } 246 247 getDataFromUdmf(event: DragEvent, callback: (data: DragEvent) => void) { 248 if (this.getDataFromUdmfRetry(event, callback)) { 249 return; 250 } 251 setTimeout(() => { 252 this.getDataFromUdmfRetry(event, callback); 253 }, 1500); 254 } 255 256 build() { 257 Row() { 258 Column() { 259 Text('start Drag') 260 .fontSize(18) 261 .width('100%') 262 .height(40) 263 .margin(10) 264 .backgroundColor('#008888') 265 Image($r('app.media.icon')) 266 .width(100) 267 .height(100) 268 .draggable(true) 269 .margin({ left: 15 }) 270 .visibility(this.imgState) 271 .onDragEnd((event) => { 272 // The result value obtained from onDragEnd is set in onDrop of the drop target. 273 if (event.getResult() === DragResult.DRAG_SUCCESSFUL) { 274 promptAction.showToast({ duration: 100, message: 'Drag Success' }); 275 } else if (event.getResult() === DragResult.DRAG_FAILED) { 276 promptAction.showToast({ duration: 100, message: 'Drag failed' }); 277 } 278 }) 279 Text('test drag event') 280 .width('100%') 281 .height(100) 282 .draggable(true) 283 .margin({ left: 15 }) 284 .copyOption(CopyOptions.InApp) 285 TextArea({ placeholder: 'please input words' }) 286 .copyOption(CopyOptions.InApp) 287 .width('100%') 288 .height(50) 289 .draggable(true) 290 Search({ placeholder: 'please input you word' }) 291 .searchButton('Search') 292 .width('100%') 293 .height(80) 294 .textFont({ size: 20 }) 295 Column() { 296 Text('change video source') 297 }.draggable(true) 298 .onDragStart((event) => { 299 let video: UDC.Video = new UDC.Video(); 300 video.videoUri = '/resources/rawfile/01.mp4'; 301 let data: UDC.UnifiedData = new UDC.UnifiedData(video); 302 (event as DragEvent).setData(data); 303 return { builder: () => { 304 this.pixelMapBuilder() 305 }, extraInfo: 'extra info' }; 306 }) 307 308 Column() { 309 Text('this is abstract') 310 .fontSize(20) 311 .width('100%') 312 }.margin({ left: 40, top: 20 }) 313 .width('100%') 314 .height(100) 315 .onDragStart((event) => { 316 let data: UDC.PlainText = new UDC.PlainText(); 317 data.abstract = 'this is abstract'; 318 data.textContent = 'this is content this is content'; 319 (event as DragEvent).setData(new UDC.UnifiedData(data)); 320 }) 321 }.width('45%') 322 .height('100%') 323 324 Column() { 325 Text('Drag Target Area') 326 .fontSize(20) 327 .width('100%') 328 .height(40) 329 .margin(10) 330 .backgroundColor('#008888') 331 Image(this.targetImage) 332 .width(this.imageWidth) 333 .height(this.imageHeight) 334 .draggable(true) 335 .margin({ left: 15 }) 336 .border({ color: Color.Black, width: 1 }) 337 .allowDrop([UTD.UniformDataType.IMAGE]) 338 .onDrop((dragEvent?: DragEvent) => { 339 this.getDataFromUdmf((dragEvent as DragEvent), (event: DragEvent) => { 340 let records: Array<UDC.UnifiedRecord> = event.getData().getRecords(); 341 let rect: Rectangle = event.getPreviewRect(); 342 this.imageWidth = Number(rect.width); 343 this.imageHeight = Number(rect.height); 344 this.targetImage = (records[0] as UDC.Image).imageUri; 345 event.useCustomDropAnimation = false; 346 animateTo({ duration: 1000 }, () => { 347 this.imageWidth = 100; 348 this.imageHeight = 100; 349 this.imgState = Visibility.None; 350 }) 351 // If result is explicitly set to successful, the value is passed in to onDragEnd of the drag source. 352 event.setResult(DragResult.DRAG_SUCCESSFUL); 353 }) 354 }) 355 356 Text(this.targetText) 357 .width('100%') 358 .height(100) 359 .border({ color: Color.Black, width: 1 }) 360 .margin(15) 361 .allowDrop([UTD.UniformDataType.TEXT]) 362 .onDrop((dragEvent?: DragEvent) => { 363 this.getDataFromUdmf((dragEvent as DragEvent), (event: DragEvent) => { 364 let records: Array<UDC.UnifiedRecord> = event.getData().getRecords(); 365 let plainText: UDC.PlainText = records[0] as UDC.PlainText; 366 this.targetText = plainText.textContent; 367 }) 368 }) 369 370 Video({ src: this.videoSrc, previewUri: $r('app.media.icon') }) 371 .width('100%') 372 .height(200) 373 .controls(true) 374 .allowDrop([UTD.UniformDataType.VIDEO]) 375 376 Column() { 377 Text(this.abstractContent).fontSize(20).width('100%') 378 Text(this.textContent).fontSize(15).width('100%') 379 } 380 .width('100%') 381 .height(100) 382 .margin(20) 383 .border({ color: Color.Black, width: 1 }) 384 .allowDrop([UTD.UniformDataType.PLAIN_TEXT]) 385 .onDrop((dragEvent?: DragEvent) => { 386 this.getDataFromUdmf((dragEvent as DragEvent), (event: DragEvent) => { 387 let records: Array<UDC.UnifiedRecord> = event.getData().getRecords(); 388 let plainText: UDC.PlainText = records[0] as UDC.PlainText; 389 this.abstractContent = plainText.abstract as string; 390 this.textContent = plainText.textContent; 391 }) 392 }) 393 }.width('45%') 394 .height('100%') 395 .margin({ left: '5%' }) 396 } 397 .height('100%') 398 } 399} 400``` 401