• 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>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#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.|
112
113## DragPreviewMode<sup>11+</sup>
114
115**Atomic service API**: This API can be used in atomic services since API version 12.
116
117| Name| Value| Description|
118| -------- | ------- | -------- |
119| 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.|
120| DISABLE_SCALE  | 2 | Disables the system's scaling behavior for the drag preview.|
121| ENABLE_DEFAULT_SHADOW<sup>12+</sup> | 3 | Enables the default shadow effect for non-text components.|
122| 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.|
123
124## DragInteractionOptions<sup>12+</sup>
125
126**Atomic service API**: This API can be used in atomic services since API version 12.
127
128| Name| Type| Mandatory| Description|
129| -------- | -------- | -------- | -------- |
130| 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>|
131| 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>|
132| isLiftingDisabled<sup>15+</sup> | boolean | No| Whether to disable 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**|
133
134## Example
135### Example 1: Allowing Drag and Drop
136
137This example demonstrates how to configure whether a component can be dragged and dropped into by setting **allowDrop** and **draggable**.
138
139```ts
140// xxx.ets
141import { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData';
142
143@Entry
144@Component
145struct ImageExample {
146  @State uri: string = ""
147  @State AblockArr: string[] = []
148  @State BblockArr: string[] = []
149  @State AVisible: Visibility = Visibility.Visible
150  @State dragSuccess :Boolean = false
151
152  build() {
153    Column() {
154      Text('Image drag and drop')
155        .fontSize('30dp')
156      Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceAround }) {
157        Image($r('app.media.icon'))
158          .width(100)
159          .height(100)
160          .border({ width: 1 })
161          .visibility(this.AVisible)
162          .draggable(true)
163          .onDragEnd((event: DragEvent) => {
164            let ret = event.getResult();
165            if(ret == 0) {
166              console.log("enter ret == 0")
167              this.AVisible = Visibility.Hidden;
168            } else {
169              console.log("enter ret != 0")
170              this.AVisible = Visibility.Visible;
171            }
172          })
173      }
174      .margin({ bottom: 20 })
175      Row() {
176        Column(){
177          Text('Invalid drop target')
178            .fontSize('15dp')
179            .height('10%')
180          List(){
181            ForEach(this.AblockArr, (item:string, index) => {
182              ListItem() {
183                Image(item)
184                  .width(100)
185                  .height(100)
186                  .border({width: 1})
187              }
188              .margin({ left: 30 , top : 30})
189            }, (item:string) => item)
190          }
191          .height('90%')
192          .width('100%')
193          .allowDrop([uniformTypeDescriptor.UniformDataType.TEXT])
194          .onDrop((event?: DragEvent, extraParams?: string) => {
195            this.uri = JSON.parse(extraParams as string).extraInfo;
196            this.AblockArr.splice(JSON.parse(extraParams as string).insertIndex, 0, this.uri);
197            console.log("ondrop not udmf data");
198          })
199          .border({width: 1})
200        }
201        .height("50%")
202        .width("45%")
203        .border({ width: 1 })
204        .margin({ left: 12 })
205        Column(){
206          Text('Valid drop target')
207            .fontSize('15dp')
208            .height('10%')
209          List(){
210            ForEach(this.BblockArr, (item:string, index) => {
211              ListItem() {
212                Image(item)
213                  .width(100)
214                  .height(100)
215                  .border({width: 1})
216              }
217              .margin({ left: 30 , top : 30})
218            }, (item:string) => item)
219          }
220          .border({width: 1})
221          .height('90%')
222          .width('100%')
223          .allowDrop([uniformTypeDescriptor.UniformDataType.IMAGE])
224          .onDrop((event?: DragEvent, extraParams?: string) => {
225            console.log("enter onDrop")
226            let dragData:UnifiedData = (event as DragEvent).getData() as UnifiedData;
227            if(dragData != undefined) {
228              let arr:Array<unifiedDataChannel.UnifiedRecord> = dragData.getRecords();
229              if(arr.length > 0) {
230                let image = arr[0] as unifiedDataChannel.Image;
231                this.uri = image.imageUri;
232                this.BblockArr.splice(JSON.parse(extraParams as string).insertIndex, 0, this.uri);
233              } else {
234                console.log(`dragData arr is null`)
235              }
236            } else {
237              console.log(`dragData  is undefined`)
238            }
239            console.log("ondrop udmf data");
240            this.dragSuccess = true
241          })
242        }
243        .height("50%")
244        .width("45%")
245        .border({ width: 1 })
246        .margin({ left: 12 })
247      }
248    }.width('100%')
249  }
250}
251```
252
253![dragImage.gif](figures/dragImage.gif)
254
255### Example 2: Setting the Drag Preview
256
257This example demonstrates how to configure the preview displayed during the drag process using **dragPreview**.
258
259```ts
260// xxx.ets
261@Entry
262@Component
263struct DragPreviewDemo{
264  @Builder dragPreviewBuilder() {
265    Column() {
266      Text("dragPreview")
267        .width(150)
268        .height(50)
269        .fontSize(20)
270        .borderRadius(10)
271        .textAlign(TextAlign.Center)
272        .fontColor(Color.Black)
273        .backgroundColor(Color.Pink)
274    }
275  }
276
277  @Builder MenuBuilder() {
278    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
279      Text("menu item 1")
280        .fontSize(15)
281        .width(100)
282        .height(40)
283        .textAlign(TextAlign.Center)
284        .fontColor(Color.Black)
285        .backgroundColor(Color.Pink)
286      Divider()
287        .height(5)
288      Text("menu item 2")
289        .fontSize(15)
290        .width(100)
291        .height(40)
292        .textAlign(TextAlign.Center)
293        .fontColor(Color.Black)
294        .backgroundColor(Color.Pink)
295    }
296    .width(100)
297  }
298
299  build() {
300    Row() {
301      Column() {
302        Image('/resource/image.jpeg')
303          .width("30%")
304          .draggable(true)
305          .bindContextMenu(this.MenuBuilder, ResponseType.LongPress)
306          .onDragStart(() => {
307            console.log("Image onDragStart")
308          })
309          .dragPreview(this.dragPreviewBuilder)
310      }
311      .width("100%")
312    }
313    .height("100%")
314  }
315}
316```
317
318![dragPreview.gif](figures/dragPreview.gif)
319
320### Example 3: Setting the Drag Preview Style
321
322This example demonstrates how to set default shadows and unified rounded corners by configuring **dragPreviewOptions** with **ENABLE_DEFAULT_SHADOW** and **ENABLE_DEFAULT_RADIUS**.
323
324```ts
325// xxx.ets
326@Entry
327@Component
328struct dragPreviewOptionsDemo{
329  build() {
330    Row() {
331      Column() {
332        Image('/resource/image.jpeg')
333          .margin({ top: 10 })
334          .width("100%")
335          .draggable(true)
336          .dragPreviewOptions({ mode: DragPreviewMode.AUTO })
337        Image('/resource/image.jpeg')
338          .margin({ top: 10 })
339          .width("80%")
340          .border({ radius: { topLeft: 1, topRight: 2, bottomLeft: 4, bottomRight: 8 } })
341          .draggable(true)
342          .dragPreviewOptions({ mode: [ DragPreviewMode.ENABLE_DEFAULT_SHADOW, DragPreviewMode.ENABLE_DEFAULT_RADIUS ] })
343      }
344      .width("100%")
345      .height("100%")
346    }
347  }
348}
349```
350
351![dragPreviewOptions.gif](figures/dragPreviewOptions.gif)
352
353
354### Example 4: Enabling Multiselect for Dragging
355
356This example demonstrates how to enable multiselect for dragging in a **Grid** component by configuring **isMultiSelectionEnabled**.
357
358```ts
359@Entry
360@Component
361struct Example {
362  @State numbers: number[] = [0, 1, 2, 3, 4 , 5, 6, 7, 8]
363  build() {
364    Column({ space: 5}) {
365      Grid() {
366        ForEach(this.numbers, (item: number) => {
367          GridItem() {
368            Column()
369              .backgroundColor(Color.Blue)
370              .width('100%')
371              .height('100%')
372          }
373          .width(90)
374          .height(90)
375          .selectable(true)
376          .selected(true)
377          .dragPreviewOptions({}, {isMultiSelectionEnabled:true})
378          .onDragStart(()=>{
379
380          })
381    }, (item: string) => item)
382      }
383      .columnsTemplate('1fr 1fr 1fr')
384      .rowsTemplate('1fr 1fr 1fr')
385      .height(300)
386    }
387    .width('100%')
388  }
389}
390```
391
392![isMultiSelectionEnabled.gif](figures/isMultiSelectionEnabled.gif)
393
394### Example 5: Enabling the Default Pressed State Animation
395
396This example demonstrates how to enable the default pressed state animation for a **Grid** component by configuring **defaultAnimationBeforeLifting**.
397
398```ts
399@Entry
400@Component
401struct Example {
402  @State numbers: number[] = [0, 1, 2, 3, 4 , 5, 6, 7, 8]
403  build() {
404    Column({ space: 5}) {
405      Grid() {
406        ForEach(this.numbers, (item: number) => {
407          GridItem() {
408            Column()
409              .backgroundColor(Color.Blue)
410              .width('100%')
411              .height('100%')
412          }
413          .width(90)
414          .height(90)
415          .selectable(true)
416          .selected(true)
417          .dragPreviewOptions({}, {isMultiSelectionEnabled:true, defaultAnimationBeforeLifting:true})
418          .onDragStart(()=>{
419
420          })
421    }, (item: string) => item)
422      }
423      .columnsTemplate('1fr 1fr 1fr')
424      .rowsTemplate('1fr 1fr 1fr')
425      .height(300)
426    }
427    .width('100%')
428  }
429}
430```
431
432![defaultAnimationBeforeLifting.gif](figures/defaultAnimationBeforeLifting.gif)
433
434### Example 6: Customizing the Preview Style
435
436This example demonstrates how to customize the preview style for an **Image** component by configuring **ImageModifier**.
437
438```ts
439// xxx.ets
440import { ImageModifier } from '@kit.ArkUI'
441
442@Entry
443@Component
444struct dragPreviewOptionsDemo{
445  @State myModifier: ImageAttribute = new ImageModifier().opacity(0.5)
446  @State vis: boolean = true
447  @State changeValue: string = ''
448  @State submitValue: string = ''
449  @State positionInfo: CaretOffset = { index: 0, x: 0, y: 0 }
450  controller: SearchController = new SearchController()
451  @State OpacityIndex: number = 0
452  @State OpacityList:(number | undefined | null)[]=[
453    0.3,0.5,0.7,1,-50,0,10,undefined,null
454  ]
455  build() {
456    Row() {
457      Column() {
458        Text(this.OpacityList[this.OpacityIndex] + "")
459        Button("Opacity")
460          .onClick(()=> {
461            this.OpacityIndex++
462            if(this.OpacityIndex > this.OpacityList.length - 1){
463              this.OpacityIndex = 0
464            }
465          })
466        Image($r('app.media.image'))
467          .margin({ top: 10 })
468          .width("100%")
469          .draggable(true)
470          .dragPreviewOptions({modifier: this.myModifier.opacity(this.OpacityList[this.OpacityIndex]) as ImageModifier})
471      }
472      .width("50%")
473      .height("50%")
474    }
475  }
476}
477```
478
479![imageModifier.gif](figures/imageModifier.gif)
480
481### Example 7: Configuring Image Dragging Settings
482
483This example shows the settings for different types of images (online image resources, local image resources, and PixelMap) during drag operations.
484The **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).
485
486```ts
487// xxx.ets
488import { uniformTypeDescriptor, unifiedDataChannel } from '@kit.ArkData';
489import { image } from '@kit.ImageKit';
490import { request } from '@kit.BasicServicesKit';
491import { common } from '@kit.AbilityKit';
492import { fileIo } from '@kit.CoreFileKit';
493import { buffer } from '@kit.ArkTS';
494import { BusinessError } from '@kit.BasicServicesKit';
495
496@Entry
497@Component
498struct ImageDrag {
499  @State targetImage1: string | PixelMap | null = null;
500  @State targetImage2: string | PixelMap | null = null;
501  @State targetImage3: string | PixelMap | null = null;
502  context = getContext(this) as common.UIAbilityContext;
503  filesDir = this.context.filesDir;
504
505  public async createPixelMap(pixelMap: unifiedDataChannel.SystemDefinedPixelMap): Promise<image.PixelMap | null> {
506    let mWidth: number = (pixelMap.details?.width ?? -1) as number;
507    let mHeight: number = (pixelMap.details?.width ?? -1) as number;
508    let mPixelFormat: image.PixelMapFormat =
509      (pixelMap.details?.['pixel-format'] ?? image.PixelMapFormat.UNKNOWN) as image.PixelMapFormat;
510    let mItemPixelMapData: Uint8Array = pixelMap.rawData;
511    const opts: image.InitializationOptions = {
512      editable: false, pixelFormat: mPixelFormat, size: {
513        height: mHeight,
514        width: mWidth
515      }
516    };
517    const buffer: ArrayBuffer = mItemPixelMapData.buffer.slice(mItemPixelMapData.byteOffset,
518      mItemPixelMapData.byteLength + mItemPixelMapData.byteOffset);
519    try {
520      let pixelMap: image.PixelMap = await image.createPixelMap(buffer, opts);
521      return pixelMap;
522    } catch (err) {
523      console.error('dragtest--> getPixelMap', err);
524      return null;
525    }
526  }
527
528  build() {
529    Column() {
530      Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Center }) {
531        // Drag an online image.
532        Column() {
533          Text('Online Image').fontSize(14)
534          Image('https://www.example.com/xxx.png') // Enter a specific online image URL.
535            .objectFit(ImageFit.Contain).draggable(true)
536            .onDragStart(() => {})
537            .width(100).height(100)
538        }
539        .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted })
540        .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)
541
542        // Drag a local image.
543        Column() {
544          Text('Local Image').fontSize(14)
545          Image($r('app.media.example'))
546            .objectFit(ImageFit.Contain).draggable(true)
547            .onDragStart(() => {})
548            .width(100).height(100)
549        }
550        .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted })
551        .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)
552
553        // Drag a PixelMap object.
554        Column() {
555          Text('PixelMap').fontSize(14)
556          Image(this.context.resourceManager.getDrawableDescriptor($r('app.media.example').id).getPixelMap())
557            .objectFit(ImageFit.Contain).draggable(true)
558            .onDragStart(() => {})
559            .width(100).height(100)
560        }
561        .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted })
562        .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)
563      }
564
565      // Set the drop data type to Image.
566      Text('Data type is Image').fontSize(14).margin({ top: 10 })
567      Column() {
568        Image(this.targetImage1)
569          .objectFit(ImageFit.Contain)
570          .width('70%').height('70%')
571          .allowDrop([uniformTypeDescriptor.UniformDataType.IMAGE])
572          .onDrop((event: DragEvent, extraParams: string) => {
573            // Obtain the image through extraParams.
574            let arr: Record<string, object> = JSON.parse(extraParams) as Record<string, object>;
575            let uri = arr['extraInfo'];
576            if (typeof uri == 'string') {
577              this.targetImage1 = uri;
578
579              try {
580                request.downloadFile(this.context, {
581                  url: uri,
582                  filePath: this.filesDir + '/example.png'
583                }).then((downloadTask: request.DownloadTask) => {
584                  let file = fileIo.openSync(this.filesDir + '/example.png', fileIo.OpenMode.READ_WRITE);
585                  let arrayBuffer = new ArrayBuffer(1024);
586                  let readLen = fileIo.readSync(file.fd, arrayBuffer);
587                  let buf = buffer.from(arrayBuffer, 0, readLen);
588                  console.info(`The content of file: ${buf.toString()}`);
589                  fileIo.closeSync(file);
590                })
591              } catch (error) {}
592            }
593          })
594      }
595      .width('70%').height('25%')
596      .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted })
597      .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)
598
599      Column() {
600        Image(this.targetImage2)
601          .objectFit(ImageFit.Contain)
602          .width('70%').height('70%')
603          .allowDrop([uniformTypeDescriptor.UniformDataType.IMAGE])
604          .onDrop((event: DragEvent, extraParams: string) => {
605            // Obtain the image through uniformTypeDescriptor.
606            let data: UnifiedData = event.getData();
607            let records: Array<unifiedDataChannel.UnifiedRecord> = data.getRecords();
608            if (records[0].getType() ===uniformTypeDescriptor.UniformDataType.IMAGE) {
609              let image: unifiedDataChannel.Image = records[0] as unifiedDataChannel.Image;
610              this.targetImage2 = image.imageUri;
611            }
612          })
613      }
614      .width('70%').height('25%')
615      .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted })
616      .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)
617
618      // Set the drop data type to PixelMap.
619      Text('Data type is PixelMap').fontSize(14).margin({ top: 10 })
620      Column() {
621        Image(this.targetImage3)
622          .objectFit(ImageFit.Contain)
623          .width('70%').height('70%')
624          .allowDrop([uniformTypeDescriptor.UniformDataType.OPENHARMONY_PIXEL_MAP])
625          .onDrop(async (event: DragEvent, extraParams: string) => {
626            // Obtain the image through uniformTypeDescriptor.
627            let data: UnifiedData = event.getData();
628            let records: Array<unifiedDataChannel.UnifiedRecord> = data.getRecords();
629            if (records[0].getType() ===uniformTypeDescriptor.UniformDataType.OPENHARMONY_PIXEL_MAP) {
630              let record: unifiedDataChannel.SystemDefinedPixelMap = records[0] as unifiedDataChannel.SystemDefinedPixelMap;
631              this.targetImage3 = await this.createPixelMap(record);
632
633              // Save data to local storage.
634              const imagePackerApi = image.createImagePacker();
635              let packOpts : image.PackingOption = { format: "image/jpeg", quality:98 };
636              const path : string = this.context.cacheDir + "/pixel_map.jpg";
637              let file = fileIo.openSync(path, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE);
638              imagePackerApi.packToFile(this.targetImage3, file.fd, packOpts).then(() => {
639                // Pack the image into the file.
640              }).catch((error : BusinessError) => {
641                console.error('Failed to pack the image. And the error is: ' + error);
642              })
643            }
644          })
645      }
646      .width('70%').height('25%')
647      .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted })
648      .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)
649
650    }.width('100%').height('100%')
651  }
652}
653```
654
655![imageDrag.gif](figures/imageDrag.gif)
656### Example 8: Customizing the Drag Preview
657This example demonstrates how to customize the drag preview using **onlyForLifting** for lifting effects and **isLiftingDisabled** to disable the lifting effect.
658```ts
659// xxx.ets
660@Entry
661@Component
662struct LiftingExampleDemo {
663  @Builder
664  dragPreviewBuilder() {
665    Column() {
666      Text("dragPreview builder")
667        .width(150)
668        .height(50)
669        .fontSize(20)
670        .borderRadius(10)
671        .textAlign(TextAlign.Center)
672        .fontColor(Color.Black)
673        .backgroundColor(Color.Green)
674    }
675  }
676  @Builder
677  MenuBuilder() {
678    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
679      Text("menu 1")
680        .fontSize(25)
681        .width(200)
682        .height(60)
683        .textAlign(TextAlign.Center)
684        .fontColor(Color.Black)
685        .backgroundColor(Color.Green)
686      Divider()
687        .height(5)
688      Text("menu 2")
689        .fontSize(25)
690        .width(200)
691        .height(60)
692        .textAlign(TextAlign.Center)
693        .fontColor(Color.Black)
694        .backgroundColor(Color.Green)
695    }
696    .width(100)
697  }
698  build() {
699    Column() {
700      Column() {
701        Text("Lifting effect disabled")
702          .fontSize(30)
703          .height(30)
704          .backgroundColor('#FFFFFF')
705          .margin({ top: 30 })
706        Image($r('app.media.startIcon'))
707          .width("40%")
708          .draggable(true)
709          .margin({ top: 15 })
710          .bindContextMenu(this.MenuBuilder, ResponseType.LongPress)
711          .onDragStart(() => {
712          })
713          .dragPreviewOptions({}, {
714            isLiftingDisabled: true
715          })
716          .dragPreview(this.dragPreviewBuilder, {
717            onlyForLifting: true,
718            delayCreating: true
719          })
720      }.width("%")
721      Column() {
722        Text("Lifting effect only")
723          .fontSize(30)
724          .height(30)
725          .backgroundColor('#FFFFFF')
726          .margin({ top: 80 })
727        Image($r('app.media.startIcon'))
728          .width("40%")
729          .draggable(true)
730          .margin({ top: 15 })
731          .onDragStart(() => {
732          })
733          .dragPreviewOptions({}, {
734            isLiftingDisabled: false
735          })
736          .dragPreview(this.dragPreviewBuilder, {
737            onlyForLifting: true,
738            delayCreating: true
739          })
740      }.width("100%")
741    }.height("100%")
742  }
743}
744```
745
746Custom preview for the lifting effect only
747
748![onlyForLifting.gif](figures/onlyForLifting.gif)
749
750Custom preview with the lifting effect disabled
751
752![isLiftingDisabled.gif](figures/isLiftingDisabled.gif)
753