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