1# Drag and Drop Control 2 3The drag and drop control attributes set whether a component can respond to drag events. 4 5> **NOTE** 6> 7> The APIs of this module are supported since API version 10. Updates will be marked with a superscript to indicate their earliest API version. 8 9The ArkUI framework implements the drag and drop capability for some 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** attribute to **true**.<!--RP1--><!--RP1End--> 10 11- The following component supports drag actions by default: [Search](ts-basic-components-search.md), [TextInput](ts-basic-components-textinput.md), [TextArea](ts-basic-components-textarea.md), [RichEditor](ts-basic-components-richeditor.md), [Text](ts-basic-components-text.md), [Image](ts-basic-components-image.md), <!--Del-->[FormComponent](ts-basic-components-formcomponent-sys.md), <!--DelEnd-->[Hyperlink](ts-container-hyperlink.md) 12 13- The following component supports drop actions by default: [Search](ts-basic-components-search.md), [TextInput](ts-basic-components-textinput.md), [TextArea](ts-basic-components-textarea.md), [Video](ts-media-components-video.md), [RichEditor](ts-basic-components-richeditor.md) 14 15You can also define drag responses by implementing common drag events. 16 17To 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**. 18 19## allowDrop 20 21allowDrop(value: Array<UniformDataType> | null) 22 23Sets the type of data that can be dropped to the component. 24 25**Atomic service API**: This API can be used in atomic services since API version 11. 26 27**System capability**: SystemCapability.ArkUI.ArkUI.Full 28 29**Parameters** 30 31| Name| Type | Mandatory| Description | 32| ------ | ------------------------------------------------------------ | ---- | ----------------------------------------------- | 33| value | Array\<[UniformDataType](../../apis-arkdata/js-apis-data-uniformTypeDescriptor.md#uniformdatatype)> \| null<sup>12+</sup> | Yes | Type of data that can be dropped to the component. Since API version 12, this parameter can be set to **null** to make the component reject all data types.<br>Default value: empty| 34 35## draggable 36 37draggable(value: boolean) 38 39Sets whether the component is draggable. 40 41**Atomic service API**: This API can be used in atomic services since API version 11. 42 43**System capability**: SystemCapability.ArkUI.ArkUI.Full 44 45**Parameters** 46 47| Name| Type | Mandatory| Description | 48| ------ | ------- | ---- | ---------------------------------------------- | 49| value | boolean | Yes | Whether the component is draggable.<br>Default value: **false**| 50 51## dragPreview<sup>11+</sup> 52 53dragPreview(value: CustomBuilder | DragItemInfo | string) 54 55Sets the preview displayed when the component is dragged 56 57**Atomic service API**: This API can be used in atomic services since API version 12. 58 59**System capability**: SystemCapability.ArkUI.ArkUI.Full 60 61**Parameters** 62 63| Name| Type | Mandatory| Description | 64| ------ | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ | 65| value | [CustomBuilder](ts-types.md#custombuilder8) \| [DragItemInfo](ts-universal-events-drag-drop.md#dragiteminfo) \| string<sup>12+</sup> | Yes | Preview displayed when the component is dragged. This attribute has effect for **onDragStart** only.<br>If the component supports drag and drop and a preview is specified through [bindContextMenu](ts-universal-attributes-menu.md#bindcontextmenu8), that specified preview is displayed when the component is dragged. The priority of the background image returned in [onDragStart](ts-universal-events-drag-drop.md#onDragStart) is lower than that of the preview set in [dragPreview](ts-universal-attributes-drag-drop.md#dragPreview11). This means that, once set, the latter will be used in place of the former. Because [CustomBuilder](ts-types.md#custombuilder8) can be used only after offline rendering, it may increase performance overhead and latency. In light of this, you are advised to use [PixelMap](../../apis-image-kit/js-apis-image.md#pixelmap7) in [DragItemInfo](ts-universal-events-drag-drop.md#dragiteminfo) to set the preview.<br> When an ID of the string type is passed in, the snapshot of the component assigned the ID is used as the preview image. If the component assigned the ID cannot be found or its **Visibility** attribute is set to **none** or **hidden**, a snapshot of the current component is used as the preview image. Currently, snapshots do not support visual effects, such as brightness, shadow, blur, and rotation.<br>Default value: empty<br>| 66 67## dragPreviewOptions<sup>11+</sup> 68 69dragPreviewOptions(value: DragPreviewOptions, options?: DragInteractionOptions) 70 71Sets the processing mode of the drag preview and the display of the number badge during dragging. The **onItemDragStart** dragging mode is not supported. 72 73**Atomic service API**: This API can be used in atomic services since API version 12. 74 75**System capability**: SystemCapability.ArkUI.ArkUI.Full 76 77**Parameters** 78 79| Name| Type | Mandatory| Description | 80| ------ | -------------------------------------------------------------- | ---- | ------------------------------------------------------------ | 81| value | [DragPreviewOptions](#dragpreviewoptions11)<sup>11+</sup> | Yes | Processing mode of the drag preview and the display of the number badge during dragging.<br>Default value: empty| 82| options<sup>12+</sup>| [DragInteractionOptions](#draginteractionoptions12)<sup>12+</sup>| No | Interaction mode of the drag preview.<br>Default value: empty| 83 84## DragPreviewOptions<sup>11+</sup> 85 86**Atomic service API**: This API can be used in atomic services since API version 12. 87 88| Name| Type| Mandatory| Description| 89| -------- | -------- | -------- | -------- | 90| mode | [DragPreviewMode](#dragpreviewmode11) \| Array<[DragPreviewMode](#dragpreviewmode11)><sup>12+</sup>| No| How the background image is processed when the component is dragged.<br>Default value: **DragPreviewMode.AUTO**<br>If **DragPreviewMode.AUTO** is along with other enum values, the setting takes precedence with **DragPreviewMode.AUTO**, and other enum values do not take effect.| 91| numberBadge<sup>12+</sup> | boolean \| number | No| Whether to display the badge or the number displayed via the badge. For a number badge, the value range is [0, 2<sup>31</sup>-1]. If the value specified is a floating-point number, only the integer part is displayed<br>**NOTE**<br>When multiple items are dragged, use this API to set the number of items dragged.<br>Default value: **true**| 92| modifier<sup>12+</sup> | [ImageModifier](ts-universal-attributes-attribute-modifier.md)| No| Style modifier to apply to the drag preview. You can use the attributes and styles supported by the image component to configure the drag preview style (see example 6). Currently, opacity, shadow, background blur, and rounded corners are supported. This parameter does not work for text dragging, which only supports the default effect.<br>1. Opacity<br>Use the [opacity](ts-universal-attributes-opacity.md#opacity) attribute to set the opacity. The value ranges from 0 to 1. If the value is set to **0** or left unspecified, it reverts to the default value **0.95**. Setting it to **1** or an invalid value makes the object completely opaque.<br>2. Shadow<br>Use the [shadow](ts-universal-attributes-image-effect.md#shadow) attribute to set the shadow.<br>3. Background blur<br>Use the [backgroundEffect](ts-universal-attributes-background.md#backgroundeffect11) or [backgroundBlurStyle](ts-universal-attributes-background.md#backgroundblurstyle9) attribute to set the background blur. If both are used, **backgroundEffect** takes precedence.<br>4. Rounded corner<br>Use the [border](ts-universal-attributes-border.md#border) or [borderRadius](ts-universal-attributes-border.md#borderRadius) attribute to set rounded corners. If you set rounded corners in both **mode** and **modifier**, the settings in **modifier** prevail.<br>Default value: empty. The attribute cannot be modified.| 93 94## DragPreviewMode<sup>11+</sup> 95 96**Atomic service API**: This API can be used in atomic services since API version 12. 97 98| Name| Value| Description| 99| -------- | ------- | -------- | 100| AUTO | 1 | The system automatically changes the position of the dragged point based on the scenario and scales the drag preview based on set rules.| 101| DISABLE_SCALE | 2 | The system does not scale the drag preview.| 102| ENABLE_DEFAULT_SHADOW<sup>12+</sup> | 3 | The default shadow effect is enabled for non-text components.| 103| ENABLE_DEFAULT_RADIUS<sup>12+</sup> | 4 | The default rounded corners (12 vp) are used for non-text components. If the custom rounded corner value set by the application is greater than the default value or the value set by **modifier**, the custom value is used.| 104 105## DragInteractionOptions<sup>12+</sup> 106 107**Atomic service API**: This API can be used in atomic services since API version 12. 108 109| Name| Type| Mandatory| Description| 110| -------- | -------- | -------- | -------- | 111| isMultiSelectionEnabled | boolean | No| Whether to enable multiselect for the drag preview. This parameter takes effect only for the [grid items](ts-container-griditem.md) and [list items](ts-container-listitem.md) in the [\<Grid>](ts-container-grid.md) and [\<List>](ts-container-list.md) containers.<br>When multiselect is enabled for an item, the child components of the item cannot be dragged. The precendence levels of drag previews for multiselect, from high to low, are as follows: preview specified through a string value in [dragPreview](#dragpreview11), preview specified through **PixelMap** in **dragPreview**, and component snapshot. The Builder format in **dragPreview** is not supported.<br>The context menu bound to the component through [bindContextMenu](ts-universal-attributes-menu.md#bindcontextmenu12) cannot contain the **isShown** parameter.<br>Default value: **false**<br>| 112| defaultAnimationBeforeLifting | boolean | No| Whether to enable the default pressed state animation (compressing in size) of the component before a lift animation starts.<br>Default value: **false**<br>| 113 114## Example 115### Example 1 116Example of using the **allowDrop** and **draggable** attributes: 117 118```ts 119// xxx.ets 120import { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData'; 121 122@Entry 123@Component 124struct ImageExample { 125 @State uri: string = "" 126 @State AblockArr: string[] = [] 127 @State BblockArr: string[] = [] 128 @State AVisible: Visibility = Visibility.Visible 129 @State dragSuccess :Boolean = false 130 131 build() { 132 Column() { 133 Text ('Image drag and drop') 134 .fontSize('30dp') 135 Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceAround }) { 136 Image($r('app.media.icon')) 137 .width(100) 138 .height(100) 139 .border({ width: 1 }) 140 .visibility(this.AVisible) 141 .draggable(true) 142 .onDragEnd((event: DragEvent) => { 143 let ret = event.getResult(); 144 if(ret == 0) { 145 console.log("enter ret == 0") 146 this.AVisible = Visibility.Hidden; 147 } else { 148 console.log("enter ret != 0") 149 this.AVisible = Visibility.Visible; 150 } 151 }) 152 } 153 .margin({ bottom: 20 }) 154 Row() { 155 Column(){ 156 Text('Invalid drop target') 157 .fontSize('15dp') 158 .height('10%') 159 List(){ 160 ForEach(this.AblockArr, (item:string, index) => { 161 ListItem() { 162 Image(item) 163 .width(100) 164 .height(100) 165 .border({width: 1}) 166 } 167 .margin({ left: 30 , top : 30}) 168 }, (item:string) => item) 169 } 170 .height('90%') 171 .width('100%') 172 .allowDrop([uniformTypeDescriptor.UniformDataType.TEXT]) 173 .onDrop((event?: DragEvent, extraParams?: string) => { 174 this.uri = JSON.parse(extraParams as string).extraInfo; 175 this.AblockArr.splice(JSON.parse(extraParams as string).insertIndex, 0, this.uri); 176 console.log("ondrop not udmf data"); 177 }) 178 .border({width: 1}) 179 } 180 .height("50%") 181 .width("45%") 182 .border({ width: 1 }) 183 .margin({ left: 12 }) 184 Column(){ 185 Text ('Valid drop target') 186 .fontSize('15dp') 187 .height('10%') 188 List(){ 189 ForEach(this.BblockArr, (item:string, index) => { 190 ListItem() { 191 Image(item) 192 .width(100) 193 .height(100) 194 .border({width: 1}) 195 } 196 .margin({ left: 30 , top : 30}) 197 }, (item:string) => item) 198 } 199 .border({width: 1}) 200 .height('90%') 201 .width('100%') 202 .allowDrop([uniformTypeDescriptor.UniformDataType.IMAGE]) 203 .onDrop((event?: DragEvent, extraParams?: string) => { 204 console.log("enter onDrop") 205 let dragData:UnifiedData = (event as DragEvent).getData() as UnifiedData; 206 if(dragData != undefined) { 207 let arr:Array<unifiedDataChannel.UnifiedRecord> = dragData.getRecords(); 208 if(arr.length > 0) { 209 let image = arr[0] as unifiedDataChannel.Image; 210 this.uri = image.imageUri; 211 this.BblockArr.splice(JSON.parse(extraParams as string).insertIndex, 0, this.uri); 212 } else { 213 console.log(`dragData arr is null`) 214 } 215 } else { 216 console.log(`dragData is undefined`) 217 } 218 console.log("ondrop udmf data"); 219 this.dragSuccess = true 220 }) 221 } 222 .height("50%") 223 .width("45%") 224 .border({ width: 1 }) 225 .margin({ left: 12 }) 226 } 227 }.width('100%') 228 } 229} 230``` 231 232 233 234 235 236 237 238### Example 2 239Example of using the **dragPreview** attribute: 240```ts 241// xxx.ets 242@Entry 243@Component 244struct DragPreviewDemo{ 245 @Builder dragPreviewBuilder() { 246 Column() { 247 Text("dragPreview") 248 .width(150) 249 .height(50) 250 .fontSize(20) 251 .borderRadius(10) 252 .textAlign(TextAlign.Center) 253 .fontColor(Color.Black) 254 .backgroundColor(Color.Pink) 255 } 256 } 257 258 @Builder MenuBuilder() { 259 Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { 260 Text("menu item 1") 261 .fontSize(15) 262 .width(100) 263 .height(40) 264 .textAlign(TextAlign.Center) 265 .fontColor(Color.Black) 266 .backgroundColor(Color.Pink) 267 Divider() 268 .height(5) 269 Text("menu item 2") 270 .fontSize(15) 271 .width(100) 272 .height(40) 273 .textAlign(TextAlign.Center) 274 .fontColor(Color.Black) 275 .backgroundColor(Color.Pink) 276 } 277 .width(100) 278 } 279 280 build() { 281 Row() { 282 Column() { 283 Image('/resource/image.jpeg') 284 .width("30%") 285 .draggable(true) 286 .bindContextMenu(this.MenuBuilder, ResponseType.LongPress) 287 .onDragStart(() => { 288 console.log("Image onDragStart") 289 }) 290 .dragPreview(this.dragPreviewBuilder) 291 } 292 .width("100%") 293 } 294 .height("100%") 295 } 296} 297``` 298 299 300 301### Example 3 302Example of using the **dragPreviewOptions** attribute: 303```ts 304// xxx.ets 305@Entry 306@Component 307struct dragPreviewOptionsDemo{ 308 build() { 309 Row() { 310 Column() { 311 Image('/resource/image.jpeg') 312 .margin({ top: 10 }) 313 .width("100%") 314 .draggable(true) 315 .dragPreviewOptions({ mode: DragPreviewMode.AUTO }) 316 Image('/resource/image.jpeg') 317 .margin({ top: 10 }) 318 .width("80%") 319 .border({ radius: { topLeft: 1, topRight: 2, bottomLeft: 4, bottomRight: 8 } }) 320 .draggable(true) 321 .dragPreviewOptions({ mode: [ DragPreviewMode.ENABLE_DEFAULT_SHADOW, DragPreviewMode.ENABLE_DEFAULT_RADIUS ] }) 322 } 323 .width("100%") 324 .height("100%") 325 } 326 } 327} 328``` 329 330 331 332 333### Example 4 334Example of using the **isMultiSelectionEnabled** parameter in **DragInteractionOptions**: 335```ts 336@Entry 337@Component 338struct Example { 339 @State numbers: number[] = [0, 1, 2, 3, 4 , 5, 6, 7, 8] 340 build() { 341 Column({ space: 5}) { 342 Grid() { 343 ForEach(this.numbers, (item: number) => { 344 GridItem() { 345 Column() 346 .backgroundColor(Color.Red) 347 .width('100%') 348 .height('100%') 349 } 350 .width(90) 351 .height(90) 352 .selectable(true) 353 .selected(true) 354 .dragPreviewOptions({}, {isMultiSelectionEnabled:true}) 355 .onDragStart(()=>{ 356 357 }) 358 }, (item: string) => item) 359 } 360 .columnsTemplate('1fr 1fr 1fr') 361 .rowsTemplate('1fr 1fr 1fr') 362 .height(300) 363 } 364 .width('100%') 365 } 366} 367``` 368 369 370 371### Example 5 372Example of using the **defaultAnimationBeforeLifting** parameter in **DragInteractionOptions**: 373```ts 374@Entry 375@Component 376struct Example { 377 @State numbers: number[] = [0, 1, 2, 3, 4 , 5, 6, 7, 8] 378 build() { 379 Column({ space: 5}) { 380 Grid() { 381 ForEach(this.numbers, (item: number) => { 382 GridItem() { 383 Column() 384 .backgroundColor(Color.Red) 385 .width('100%') 386 .height('100%') 387 } 388 .width(90) 389 .height(90) 390 .selectable(true) 391 .selected(true) 392 .dragPreviewOptions({}, {isMultiSelectionEnabled:true, defaultAnimationBeforeLifting:true}) 393 .onDragStart(()=>{ 394 395 }) 396 }, (item: string) => item) 397 } 398 .columnsTemplate('1fr 1fr 1fr') 399 .rowsTemplate('1fr 1fr 1fr') 400 .height(300) 401 } 402 .width('100%') 403 } 404} 405``` 406 407 408 409### Example 6 410This example shows how to use the **ImageModifier** parameter in **dragPreviewOptions**. 411```ts 412// xxx.ets 413import { ImageModifier } from '@kit.ArkUI' 414 415@Entry 416@Component 417struct dragPreviewOptionsDemo{ 418 @State myModifier: ImageAttribute = new ImageModifier().opacity(0.5) 419 @State vis: boolean = true 420 @State changeValue: string = '' 421 @State submitValue: string = '' 422 @State positionInfo: CaretOffset = { index: 0, x: 0, y: 0 } 423 controller: SearchController = new SearchController() 424 @State OpacityIndex: number = 0 425 @State OpacityList:(number | undefined | null)[]=[ 426 0.3,0.5,0.7,1,-50,0,10,undefined,null 427 ] 428 build() { 429 Row() { 430 Column() { 431 Text(this.OpacityList[this.OpacityIndex] + "") 432 Button("Opacity") 433 .onClick(()=> { 434 this.OpacityIndex++ 435 if(this.OpacityIndex > this.OpacityList.length - 1){ 436 this.OpacityIndex = 0 437 } 438 }) 439 Image($r('app.media.image')) 440 .margin({ top: 10 }) 441 .width("100%") 442 .draggable(true) 443 .dragPreviewOptions({modifier: this.myModifier.opacity(this.OpacityList[this.OpacityIndex]) as ImageModifier}) 444 } 445 .width("50%") 446 .height("50%") 447 } 448 } 449} 450``` 451 452 453