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<UniformDataType> | 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 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 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 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 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 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 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 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 749 750Custom preview with the lifting effect disabled 751 752 753