• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 provides default drag and drop capabilities 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). You can also define drag responses by implementing common drag events.
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). You can control the default drag behavior by setting the [draggable](ts-universal-attributes-drag-drop.md#draggable) attribute.
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), [RichEditor](ts-basic-components-richeditor.md). You can disable the default drag behavior by setting the [allowDrop](ts-universal-attributes-drag-drop.md#allowdrop) attribute to **null**.
14
15<!--RP1--><!--RP1End-->To 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**.
16
17> **NOTE**
18>
19> When using the **Text** component, set [copyOption](ts-basic-components-text.md#copyoption9) to **CopyOptions.InApp** or **CopyOptions.LocalDevice**.
20
21## allowDrop
22
23allowDrop(value: Array&lt;UniformDataType&gt; | null)
24
25Sets the type of data that can be dropped to the component.
26
27**Atomic service API**: This API can be used in atomic services since API version 11.
28
29**System capability**: SystemCapability.ArkUI.ArkUI.Full
30
31**Parameters**
32
33| Name| Type                                                        | Mandatory| Description                                           |
34| ------ | ------------------------------------------------------------ | ---- | ----------------------------------------------- |
35| 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|
36
37## draggable
38
39draggable(value: boolean)
40
41Sets whether the component is draggable.
42
43**Atomic service API**: This API can be used in atomic services since API version 11.
44
45**System capability**: SystemCapability.ArkUI.ArkUI.Full
46
47**Parameters**
48
49| Name| Type   | Mandatory| Description                                          |
50| ------ | ------- | ---- | ---------------------------------------------- |
51| value  | boolean | Yes  | Whether the component is draggable. <br>**true**: The component is draggable.<br>**false**: The component is not draggable.<br>Default value: **false**|
52
53## dragPreview<sup>11+</sup>
54
55dragPreview(value: CustomBuilder | DragItemInfo | string)
56
57Sets the preview displayed when the component is dragged.
58
59**Atomic service API**: This API can be used in atomic services since API version 12.
60
61**System capability**: SystemCapability.ArkUI.ArkUI.Full
62
63**Parameters**
64
65| Name| Type                                                        | Mandatory| Description                                                        |
66| ------ | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ |
67| 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>|
68
69## dragPreview<sup>15+</sup>
70
71dragPreview(preview: CustomBuilder | DragItemInfo | string, config?: PreviewConfiguration):T
72
73Sets the preview displayed when the component is dragged. It is used only for setting or disabling the lifting effect.
74
75**Atomic service API**: This API can be used in atomic services since API version 15.
76
77**System capability**: SystemCapability.ArkUI.ArkUI.Full
78
79**Parameters**
80
81| Name| Type                                                        | Mandatory| Description                                                        |
82| ------ | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ |
83| preview  | [CustomBuilder](ts-types.md#custombuilder8) \| [DragItemInfo](ts-universal-events-drag-drop.md#dragiteminfo) \| string | 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|
84| config | [PreviewConfiguration](ts-universal-events-drag-drop.md#previewconfiguration15) | Yes| Additional settings for the drag preview.<br>This parameter is effective only for previews set using [dragPreview](#dragpreview11).<br>Default value: empty|
85
86## dragPreviewOptions<sup>11+</sup>
87
88dragPreviewOptions(value: DragPreviewOptions, options?: DragInteractionOptions)
89
90Sets the processing mode of the drag preview and the display of the number badge during dragging. The **onItemDragStart** dragging mode is not supported.
91
92**Atomic service API**: This API can be used in atomic services since API version 12.
93
94**System capability**: SystemCapability.ArkUI.ArkUI.Full
95
96**Parameters**
97
98| Name| Type                                                           | Mandatory| Description                                                        |
99| ------ | -------------------------------------------------------------- | ---- | ------------------------------------------------------------ |
100| 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|
101| options<sup>12+</sup>| [DragInteractionOptions](#draginteractionoptions12)<sup>12+</sup>| No  | Interaction mode of the drag preview.<br>Default value: empty|
102
103## DragPreviewOptions<sup>11+</sup>
104
105**Atomic service API**: This API can be used in atomic services since API version 12.
106
107| Name| Type| Mandatory| Description|
108| -------- | -------- | -------- | -------- |
109| 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.|
110| numberBadge<sup>12+</sup> | boolean  \|  number | No| Whether to display the number badge or the number displayed on the badge. For a number badge, the value range is [0, 2<sup>31</sup>-1]. Values outside this range will be processed as the default state. 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**|
111| 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#backgroundblurstyle18) 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.|
112| sizeChangeEffect<sup>18+</sup> | [DraggingSizeChangeEffect](#draggingsizechangeeffect18)<sup>18+</sup> | No| Transition effect for switching between the long-press preview and the drag preview.<br>Default value: **DraggingSizeChangeEffect.DEFAULT**|
113
114## DragPreviewMode<sup>11+</sup>
115
116**Atomic service API**: This API can be used in atomic services since API version 12.
117
118| Name| Value| Description|
119| -------- | ------- | -------- |
120| AUTO  | 1 | Enables the system to automatically change the position of the dragged point based on the scenario and apply scaling transformations to the drag preview based on set rules.|
121| DISABLE_SCALE  | 2 | Disables the system's scaling behavior for the drag preview.|
122| ENABLE_DEFAULT_SHADOW<sup>12+</sup> | 3 | Enables the default shadow effect for non-text components.|
123| ENABLE_DEFAULT_RADIUS<sup>12+</sup> | 4 | Enables a unified rounded corner effect for non-text components, with the default value of 12 vp. 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.|
124| ENABLE_DRAG_ITEM_GRAY_EFFECT<sup>18+</sup> | 5 | Enables the gray (transparency) effect for the original drag item, which does not apply to text content dragging. When the user starts dragging, the original item displays a gray effect. When released, the original item returns to its original appearance. After enabling the default gray effect, avoid manually modifying the opacity after dragging starts. Otherwise, the gray effect will be overridden, and the original opacity will not be correctly restored when dragging ends.|
125| ENABLE_MULTI_TILE_EFFECT<sup>18+</sup> | 6 | Enables the effect where multiple selected objects do not cluster when dragged with the mouse. This parameter takes effect only when** isMultiSelectionEnabled** is **true** and effective under multi-selection conditions. The non-clustering effect has a higher priority than [dragPreview](#dragpreview11). This setting does not support secondary dragging, rounded corners, or scaling.|
126| ENABLE_TOUCH_POINT_CALCULATION_BASED_ON_FINAL_PREVIEW<sup>18+</sup> | 7 | Whether to enable the calculation of touch point positions based on the initial size of the drag preview. This option has no effect when **DragPreviewMode.ENABLE_MULTI_TILE_EFFECT** is set.|
127
128## DraggingSizeChangeEffect<sup>18+</sup>
129
130Enumerates the transition effects for switching between the long-press preview (set through [bindContextMenu](ts-universal-attributes-menu.md#bindcontextmenu12)) and the drag preview when both are configured on a component.
131
132**Atomic service API**: This API can be used in atomic services since API version 18.
133
134**System capability**: SystemCapability.ArkUI.ArkUI.Full
135
136| Name| Value| Description|
137| -------- | ------- | -------- |
138| DEFAULT | 0 | Directly switches from the long-press preview to the final drag preview at its full size when dragging begins.|
139| SIZE_TRANSITION | 1 | Switches from the long-press preview to the drag preview directly, but transitions the size from the long-press preview size to the final drag preview size. This is used when the long-press preview and drag preview are the same.|
140| SIZE_CONTENT_TRANSITION | 2 | Gradually transitions from the long-press preview to the final drag preview, including changes in content opacity and size. This is used when the long-press preview and drag preview have significant differences.|
141
142
143## DragInteractionOptions<sup>12+</sup>
144
145**Atomic service API**: This API can be used in atomic services since API version 12.
146
147| Name| Type| Mandatory| Description|
148| -------- | -------- | -------- | -------- |
149| isMultiSelectionEnabled | boolean | No| Whether to enable multiselect for the drag preview. <br>**true**: Enable multiselect for the drag preview.<br>**false**: Disable multiselect for the drag preview.<br> 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>|
150| defaultAnimationBeforeLifting | boolean | No| Whether to enable the default pressed state animation (compressing in size) of the component before a lift animation starts. <br>**true**: Enable the default pressed state animation.<br>**false**: Disable the default pressed state animation.<br>Default value: **false**<br>|
151| isLiftingDisabled<sup>15+</sup> | boolean | No| Whether to disable the lifting effect during dragging. <br>**true**: Disable the lifting effect during dragging.<br>**false**: Enable the lifting effect during dragging.<br>With the value **true**, only the custom menu preview (set using [bindContextMenu](ts-universal-attributes-menu.md#bindcontextmenu8)), also known as the long-press preview, is displayed if both the long-press preview and drag preview are configured.<br>Default value: **false**|
152| enableEdgeAutoScroll<sup>18+</sup> | boolean | No| Whether to trigger automatic scrolling for dragging to the edge of a scrollable component. <br>**true**: Trigger automatic scrolling.<br>**false**: Do not trigger automatic scrolling.<br>Default value: **true**|
153| enableHapticFeedback<sup>18+</sup> | boolean | No| Whether to enable haptic feedback during dragging. <br>**true**: Enable haptic feedback during dragging.<br>**false**: Disable haptic feedback during dragging. This parameter takes effect only in preview scenarios with a mask (using [bindContextMenu](ts-universal-attributes-menu.md#bindcontextmenu12)).<br>Default value: **false**|
154
155## Example
156### Example 1: Allowing Drag and Drop
157
158This example demonstrates how to configure whether a component can be dragged and dropped into by setting **allowDrop** and **draggable**.
159
160```ts
161// xxx.ets
162import { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData';
163
164@Entry
165@Component
166struct ImageExample {
167  @State uri: string = ""
168  @State AblockArr: string[] = []
169  @State BblockArr: string[] = []
170  @State AVisible: Visibility = Visibility.Visible
171  @State dragSuccess :Boolean = false
172
173  build() {
174    Column() {
175      Text('Image drag and drop')
176        .fontSize('30dp')
177      Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceAround }) {
178        Image($r('app.media.icon'))
179          .width(100)
180          .height(100)
181          .border({ width: 1 })
182          .visibility(this.AVisible)
183          .draggable(true)
184          .onDragEnd((event: DragEvent) => {
185            let ret = event.getResult();
186            if(ret == 0) {
187              console.log("enter ret == 0")
188              this.AVisible = Visibility.Hidden;
189            } else {
190              console.log("enter ret != 0")
191              this.AVisible = Visibility.Visible;
192            }
193          })
194      }
195      .margin({ bottom: 20 })
196      Row() {
197        Column(){
198          Text('Invalid drop target')
199            .fontSize('15dp')
200            .height('10%')
201          List(){
202            ForEach(this.AblockArr, (item:string, index) => {
203              ListItem() {
204                Image(item)
205                  .width(100)
206                  .height(100)
207                  .border({width: 1})
208              }
209              .margin({ left: 30 , top : 30})
210            }, (item:string) => item)
211          }
212          .height('90%')
213          .width('100%')
214          .allowDrop([uniformTypeDescriptor.UniformDataType.TEXT])
215          .onDrop((event?: DragEvent, extraParams?: string) => {
216            this.uri = JSON.parse(extraParams as string).extraInfo;
217            this.AblockArr.splice(JSON.parse(extraParams as string).insertIndex, 0, this.uri);
218            console.log("ondrop not udmf data");
219          })
220          .border({width: 1})
221        }
222        .height("50%")
223        .width("45%")
224        .border({ width: 1 })
225        .margin({ left: 12 })
226        Column(){
227          Text('Valid drop target')
228            .fontSize('15dp')
229            .height('10%')
230          List(){
231            ForEach(this.BblockArr, (item:string, index) => {
232              ListItem() {
233                Image(item)
234                  .width(100)
235                  .height(100)
236                  .border({width: 1})
237              }
238              .margin({ left: 30 , top : 30})
239            }, (item:string) => item)
240          }
241          .border({width: 1})
242          .height('90%')
243          .width('100%')
244          .allowDrop([uniformTypeDescriptor.UniformDataType.IMAGE])
245          .onDrop((event?: DragEvent, extraParams?: string) => {
246            console.log("enter onDrop")
247            let dragData:UnifiedData = (event as DragEvent).getData() as UnifiedData;
248            if(dragData != undefined) {
249              let arr:Array<unifiedDataChannel.UnifiedRecord> = dragData.getRecords();
250              if(arr.length > 0) {
251                let image = arr[0] as unifiedDataChannel.Image;
252                this.uri = image.imageUri;
253                this.BblockArr.splice(JSON.parse(extraParams as string).insertIndex, 0, this.uri);
254              } else {
255                console.log(`dragData arr is null`)
256              }
257            } else {
258              console.log(`dragData  is undefined`)
259            }
260            console.log("ondrop udmf data");
261            this.dragSuccess = true
262          })
263        }
264        .height("50%")
265        .width("45%")
266        .border({ width: 1 })
267        .margin({ left: 12 })
268      }
269    }.width('100%')
270  }
271}
272```
273
274![dragImage.gif](figures/dragImage.gif)
275
276### Example 2: Setting the Drag Preview
277
278This example demonstrates how to configure the preview displayed during the drag process using **dragPreview**.
279
280```ts
281// xxx.ets
282@Entry
283@Component
284struct DragPreviewDemo{
285  @Builder dragPreviewBuilder() {
286    Column() {
287      Text("dragPreview")
288        .width(150)
289        .height(50)
290        .fontSize(20)
291        .borderRadius(10)
292        .textAlign(TextAlign.Center)
293        .fontColor(Color.Black)
294        .backgroundColor(Color.Pink)
295    }
296  }
297
298  @Builder MenuBuilder() {
299    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
300      Text("menu item 1")
301        .fontSize(15)
302        .width(100)
303        .height(40)
304        .textAlign(TextAlign.Center)
305        .fontColor(Color.Black)
306        .backgroundColor(Color.Pink)
307      Divider()
308        .height(5)
309      Text("menu item 2")
310        .fontSize(15)
311        .width(100)
312        .height(40)
313        .textAlign(TextAlign.Center)
314        .fontColor(Color.Black)
315        .backgroundColor(Color.Pink)
316    }
317    .width(100)
318  }
319
320  build() {
321    Row() {
322      Column() {
323        Image('/resource/image.jpeg')
324          .width("30%")
325          .draggable(true)
326          .bindContextMenu(this.MenuBuilder, ResponseType.LongPress)
327          .onDragStart(() => {
328            console.log("Image onDragStart")
329          })
330          .dragPreview(this.dragPreviewBuilder)
331      }
332      .width("100%")
333    }
334    .height("100%")
335  }
336}
337```
338
339![dragPreview.gif](figures/dragPreview.gif)
340
341### Example 3: Setting the Drag Preview Style
342
343This example demonstrates how to set default shadows, unified rounded corners, and gray effects by configuring **dragPreviewOptions** with **ENABLE_DEFAULT_SHADOW**, **ENABLE_DEFAULT_RADIUS**, and **ENABLE_DRAG_ITEM_GRAY_EFFECT**.
344
345```ts
346// xxx.ets
347@Entry
348@Component
349struct dragPreviewOptionsDemo{
350  build() {
351    Row() {
352      Column() {
353        Image('/resource/image.jpeg')
354          .margin({ top: 10 })
355          .width("30%")
356          .draggable(true)
357          .dragPreviewOptions({ mode: DragPreviewMode.AUTO })
358        Image('/resource/image.jpeg')
359          .margin({ top: 10 })
360          .width("30%")
361          .border({ radius: { topLeft: 1, topRight: 2, bottomLeft: 4, bottomRight: 8 } })
362          .draggable(true)
363          .onDragStart(() => {
364            console.log("Image onDragStart")
365          })
366          .dragPreviewOptions({ mode: [ DragPreviewMode.ENABLE_DEFAULT_SHADOW, DragPreviewMode.ENABLE_DEFAULT_RADIUS, DragPreviewMode.ENABLE_DRAG_ITEM_GRAY_EFFECT ] })
367      }
368      .width("100%")
369      .height("100%")
370    }
371  }
372}
373```
374
375![dragPreviewMode.gif](figures/dragPreviewMode.gif)
376
377
378### Example 4: Enabling Multiselect for Dragging
379
380This example demonstrates how to enable multiselect for dragging in a **Grid** component by configuring **isMultiSelectionEnabled**.
381
382```ts
383@Entry
384@Component
385struct Example {
386  @State numbers: number[] = [0, 1, 2, 3, 4 , 5, 6, 7, 8]
387  build() {
388    Column({ space: 5}) {
389      Grid() {
390        ForEach(this.numbers, (item: number) => {
391          GridItem() {
392            Column()
393              .backgroundColor(Color.Blue)
394              .width('100%')
395              .height('100%')
396          }
397          .width(90)
398          .height(90)
399          .selectable(true)
400          .selected(true)
401          .dragPreviewOptions({}, {isMultiSelectionEnabled:true})
402          .onDragStart(()=>{
403
404          })
405    }, (item: string) => item)
406      }
407      .columnsTemplate('1fr 1fr 1fr')
408      .rowsTemplate('1fr 1fr 1fr')
409      .height(300)
410    }
411    .width('100%')
412  }
413}
414```
415
416![isMultiSelectionEnabled.gif](figures/isMultiSelectionEnabled.gif)
417
418### Example 5: Enabling the Default Pressed State Animation
419
420This example demonstrates how to enable the default pressed state animation for a **Grid** component by configuring **defaultAnimationBeforeLifting**.
421
422```ts
423@Entry
424@Component
425struct Example {
426  @State numbers: number[] = [0, 1, 2, 3, 4 , 5, 6, 7, 8]
427  build() {
428    Column({ space: 5}) {
429      Grid() {
430        ForEach(this.numbers, (item: number) => {
431          GridItem() {
432            Column()
433              .backgroundColor(Color.Blue)
434              .width('100%')
435              .height('100%')
436          }
437          .width(90)
438          .height(90)
439          .selectable(true)
440          .selected(true)
441          .dragPreviewOptions({}, {isMultiSelectionEnabled:true, defaultAnimationBeforeLifting:true})
442          .onDragStart(()=>{
443
444          })
445    }, (item: string) => item)
446      }
447      .columnsTemplate('1fr 1fr 1fr')
448      .rowsTemplate('1fr 1fr 1fr')
449      .height(300)
450    }
451    .width('100%')
452  }
453}
454```
455
456![defaultAnimationBeforeLifting.gif](figures/defaultAnimationBeforeLifting.gif)
457
458### Example 6: Customizing the Preview Style
459
460This example demonstrates how to customize the preview style for an **Image** component by configuring **ImageModifier**.
461
462```ts
463// xxx.ets
464import { ImageModifier } from '@kit.ArkUI'
465
466@Entry
467@Component
468struct dragPreviewOptionsDemo{
469  @State myModifier: ImageAttribute = new ImageModifier().opacity(0.5)
470  @State vis: boolean = true
471  @State changeValue: string = ''
472  @State submitValue: string = ''
473  @State positionInfo: CaretOffset = { index: 0, x: 0, y: 0 }
474  controller: SearchController = new SearchController()
475  @State OpacityIndex: number = 0
476  @State OpacityList:(number | undefined | null)[]=[
477    0.3,0.5,0.7,1,-50,0,10,undefined,null
478  ]
479  build() {
480    Row() {
481      Column() {
482        Text(this.OpacityList[this.OpacityIndex] + "")
483        Button("Opacity")
484          .onClick(()=> {
485            this.OpacityIndex++
486            if(this.OpacityIndex > this.OpacityList.length - 1){
487              this.OpacityIndex = 0
488            }
489          })
490        Image($r('app.media.image'))
491          .margin({ top: 10 })
492          .width("100%")
493          .draggable(true)
494          .dragPreviewOptions({modifier: this.myModifier.opacity(this.OpacityList[this.OpacityIndex]) as ImageModifier})
495      }
496      .width("50%")
497      .height("50%")
498    }
499  }
500}
501```
502
503![imageModifier.gif](figures/imageModifier.gif)
504
505### Example 7: Configuring Image Dragging Settings
506
507This example shows the settings for different types of images (online image resources, local image resources, and PixelMap) during drag operations.
508The **ohos.permission.INTERNET** permission is required for using online images. For details about how to apply for a permission, see [Declaring Permissions](../../../security/AccessToken/declare-permissions.md).
509
510```ts
511// xxx.ets
512import { uniformTypeDescriptor, unifiedDataChannel } from '@kit.ArkData';
513import { image } from '@kit.ImageKit';
514import { request } from '@kit.BasicServicesKit';
515import { common } from '@kit.AbilityKit';
516import { fileIo } from '@kit.CoreFileKit';
517import { buffer } from '@kit.ArkTS';
518import { BusinessError } from '@kit.BasicServicesKit';
519
520@Entry
521@Component
522struct ImageDrag {
523  @State targetImage1: string | PixelMap | null = null;
524  @State targetImage2: string | PixelMap | null = null;
525  @State targetImage3: string | PixelMap | null = null;
526  context = getContext(this) as common.UIAbilityContext;
527  filesDir = this.context.filesDir;
528
529  public async createPixelMap(pixelMap: unifiedDataChannel.SystemDefinedPixelMap): Promise<image.PixelMap | null> {
530    let mWidth: number = (pixelMap.details?.width ?? -1) as number;
531    let mHeight: number = (pixelMap.details?.width ?? -1) as number;
532    let mPixelFormat: image.PixelMapFormat =
533      (pixelMap.details?.['pixel-format'] ?? image.PixelMapFormat.UNKNOWN) as image.PixelMapFormat;
534    let mItemPixelMapData: Uint8Array = pixelMap.rawData;
535    const opts: image.InitializationOptions = {
536      editable: false, pixelFormat: mPixelFormat, size: {
537        height: mHeight,
538        width: mWidth
539      }
540    };
541    const buffer: ArrayBuffer = mItemPixelMapData.buffer.slice(mItemPixelMapData.byteOffset,
542      mItemPixelMapData.byteLength + mItemPixelMapData.byteOffset);
543    try {
544      let pixelMap: image.PixelMap = await image.createPixelMap(buffer, opts);
545      return pixelMap;
546    } catch (err) {
547      console.error('dragtest--> getPixelMap', err);
548      return null;
549    }
550  }
551
552  build() {
553    Column() {
554      Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Center }) {
555        // Drag an online image.
556        Column() {
557          Text('Online Image').fontSize(14)
558          Image('https://www.example.com/xxx.png') // Enter a specific online image URL.
559            .objectFit(ImageFit.Contain).draggable(true)
560            .onDragStart(() => {})
561            .width(100).height(100)
562        }
563        .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted })
564        .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)
565
566        // Drag a local image.
567        Column() {
568          Text('Local Image').fontSize(14)
569          Image($r('app.media.example'))
570            .objectFit(ImageFit.Contain).draggable(true)
571            .onDragStart(() => {})
572            .width(100).height(100)
573        }
574        .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted })
575        .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)
576
577        // Drag a PixelMap object.
578        Column() {
579          Text('PixelMap').fontSize(14)
580          Image(this.context.resourceManager.getDrawableDescriptor($r('app.media.example').id).getPixelMap())
581            .objectFit(ImageFit.Contain).draggable(true)
582            .onDragStart(() => {})
583            .width(100).height(100)
584        }
585        .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted })
586        .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)
587      }
588
589      // Set the drop data type to Image.
590      Text('Data type is Image').fontSize(14).margin({ top: 10 })
591      Column() {
592        Image(this.targetImage1)
593          .objectFit(ImageFit.Contain)
594          .width('70%').height('70%')
595          .allowDrop([uniformTypeDescriptor.UniformDataType.IMAGE])
596          .onDrop((event: DragEvent, extraParams: string) => {
597            // Obtain the image through extraParams.
598            let arr: Record<string, object> = JSON.parse(extraParams) as Record<string, object>;
599            let uri = arr['extraInfo'];
600            if (typeof uri == 'string') {
601              this.targetImage1 = uri;
602
603              try {
604                request.downloadFile(this.context, {
605                  url: uri,
606                  filePath: this.filesDir + '/example.png'
607                }).then((downloadTask: request.DownloadTask) => {
608                  let file = fileIo.openSync(this.filesDir + '/example.png', fileIo.OpenMode.READ_WRITE);
609                  let arrayBuffer = new ArrayBuffer(1024);
610                  let readLen = fileIo.readSync(file.fd, arrayBuffer);
611                  let buf = buffer.from(arrayBuffer, 0, readLen);
612                  console.info(`The content of file: ${buf.toString()}`);
613                  fileIo.closeSync(file);
614                })
615              } catch (error) {}
616            }
617          })
618      }
619      .width('70%').height('25%')
620      .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted })
621      .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)
622
623      Column() {
624        Image(this.targetImage2)
625          .objectFit(ImageFit.Contain)
626          .width('70%').height('70%')
627          .allowDrop([uniformTypeDescriptor.UniformDataType.IMAGE])
628          .onDrop((event: DragEvent, extraParams: string) => {
629            // Obtain the image through uniformTypeDescriptor.
630            let data: UnifiedData = event.getData();
631            let records: Array<unifiedDataChannel.UnifiedRecord> = data.getRecords();
632            if (records[0].getType() ===uniformTypeDescriptor.UniformDataType.IMAGE) {
633              let image: unifiedDataChannel.Image = records[0] as unifiedDataChannel.Image;
634              this.targetImage2 = image.imageUri;
635            }
636          })
637      }
638      .width('70%').height('25%')
639      .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted })
640      .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)
641
642      // Set the drop data type to PixelMap.
643      Text('Data type is PixelMap').fontSize(14).margin({ top: 10 })
644      Column() {
645        Image(this.targetImage3)
646          .objectFit(ImageFit.Contain)
647          .width('70%').height('70%')
648          .allowDrop([uniformTypeDescriptor.UniformDataType.OPENHARMONY_PIXEL_MAP])
649          .onDrop(async (event: DragEvent, extraParams: string) => {
650            // Obtain the image through uniformTypeDescriptor.
651            let data: UnifiedData = event.getData();
652            let records: Array<unifiedDataChannel.UnifiedRecord> = data.getRecords();
653            if (records[0].getType() ===uniformTypeDescriptor.UniformDataType.OPENHARMONY_PIXEL_MAP) {
654              let record: unifiedDataChannel.SystemDefinedPixelMap = records[0] as unifiedDataChannel.SystemDefinedPixelMap;
655              this.targetImage3 = await this.createPixelMap(record);
656
657              // Save data to local storage.
658              const imagePackerApi = image.createImagePacker();
659              let packOpts : image.PackingOption = { format: "image/jpeg", quality:98 };
660              const path : string = this.context.cacheDir + "/pixel_map.jpg";
661              let file = fileIo.openSync(path, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE);
662              imagePackerApi.packToFile(this.targetImage3, file.fd, packOpts).then(() => {
663                // Pack the image into the file.
664              }).catch((error : BusinessError) => {
665                console.error('Failed to pack the image. And the error is: ' + error);
666              })
667            }
668          })
669      }
670      .width('70%').height('25%')
671      .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted })
672      .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)
673
674    }.width('100%').height('100%')
675  }
676}
677```
678
679![imageDrag.gif](figures/imageDrag.gif)
680
681### Example 8: Enabling Haptic Feedback for Dragging
682This example demonstrates how to enable haptic feedback for image dragging by setting **enableHapticFeedback**.
683```ts
684// xxx.ets
685@Entry
686@Component
687struct DragPreviewDemo{
688  @Builder MenuBuilder() {
689    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
690      Text("menu item 1")
691        .fontSize(15)
692        .width(100)
693        .height(40)
694        .textAlign(TextAlign.Center)
695        .fontColor(Color.Black)
696        .backgroundColor(Color.Pink)
697      Divider()
698        .height(5)
699      Text("menu item 2")
700        .fontSize(15)
701        .width(100)
702        .height(40)
703        .textAlign(TextAlign.Center)
704        .fontColor(Color.Black)
705        .backgroundColor(Color.Pink)
706    }
707    .width(100)
708  }
709
710  build() {
711    Row() {
712      Column() {
713        Image($r('app.media.app_icon'))
714          .width("30%")
715          .draggable(true)
716          .dragPreviewOptions({}, {isMultiSelectionEnabled:true, defaultAnimationBeforeLifting:true, enableHapticFeedback: true})
717          .bindContextMenu(this.MenuBuilder, ResponseType.LongPress)
718          .onDragStart(() => {
719            console.log("Image onDragStart")
720          })
721      }
722      .width("100%")
723    }
724    .height("100%")
725  }
726}
727```
728
729### Example 9: Customizing the Drag Preview
730This example demonstrates how to customize the drag preview using **onlyForLifting** for lifting effects and **isLiftingDisabled** to disable the lifting effect.
731```ts
732// xxx.ets
733@Entry
734@Component
735struct LiftingExampleDemo {
736  @Builder
737  dragPreviewBuilder() {
738    Column() {
739      Text("dragPreview builder")
740        .width(150)
741        .height(50)
742        .fontSize(20)
743        .borderRadius(10)
744        .textAlign(TextAlign.Center)
745        .fontColor(Color.Black)
746        .backgroundColor(Color.Green)
747    }
748  }
749  @Builder
750  MenuBuilder() {
751    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
752      Text("menu 1")
753        .fontSize(25)
754        .width(200)
755        .height(60)
756        .textAlign(TextAlign.Center)
757        .fontColor(Color.Black)
758        .backgroundColor(Color.Green)
759      Divider()
760        .height(5)
761      Text("menu 2")
762        .fontSize(25)
763        .width(200)
764        .height(60)
765        .textAlign(TextAlign.Center)
766        .fontColor(Color.Black)
767        .backgroundColor(Color.Green)
768    }
769    .width(100)
770  }
771  build() {
772    Column() {
773      Column() {
774        Text("Lifting effect disabled")
775          .fontSize(30)
776          .height(30)
777          .backgroundColor('#FFFFFF')
778          .margin({ top: 30 })
779        Image($r('app.media.startIcon'))
780          .width("40%")
781          .draggable(true)
782          .margin({ top: 15 })
783          .bindContextMenu(this.MenuBuilder, ResponseType.LongPress)
784          .onDragStart(() => {
785          })
786          .dragPreviewOptions({}, {
787            isLiftingDisabled: true
788          })
789          .dragPreview(this.dragPreviewBuilder, {
790            onlyForLifting: true,
791            delayCreating: true
792          })
793      }.width("%")
794      Column() {
795        Text("Lifting effect only")
796          .fontSize(30)
797          .height(30)
798          .backgroundColor('#FFFFFF')
799          .margin({ top: 80 })
800        Image($r('app.media.startIcon'))
801          .width("40%")
802          .draggable(true)
803          .margin({ top: 15 })
804          .onDragStart(() => {
805          })
806          .dragPreviewOptions({}, {
807            isLiftingDisabled: false
808          })
809          .dragPreview(this.dragPreviewBuilder, {
810            onlyForLifting: true,
811            delayCreating: true
812          })
813      }.width("100%")
814    }.height("100%")
815  }
816}
817```
818
819Custom preview for the lifting effect only
820
821![onlyForLifting.gif](figures/onlyForLifting.gif)
822
823Custom preview with the lifting effect disabled
824
825![isLiftingDisabled.gif](figures/isLiftingDisabled.gif)
826