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