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&lt;UniformDataType&gt; | 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![dragImage1.jpeg](figures/dragImage1.jpeg)
233
234![dragImage2.jpeg](figures/dragImage2.jpeg)
235
236![dragImage3.jpeg](figures/dragImage3.jpeg)
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![dragPreview.gif](figures/dragPreview.gif)
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![dragPreviewOptions.gif](figures/dragPreviewOptions.gif)
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![isMultiSelectionEnabled.gif](figures/isMultiSelectionEnabled.gif)
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![defaultAnimationBeforeLifting.gif](figures/defaultAnimationBeforeLifting.gif)
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![imageModifier.gif](figures/imageModifier.gif)
453