1e41f4b71Sopenharmony_ci# Drag Event
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## Overview
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ciThe drag event, bolstered by the drag and drop framework, represents a mode of data transfer using a mouse device or gesture: Users can drag data from one component to another. The component from which data is dragged is the drag source; and the component to which data is dropped is the drop target. This drag and drop operation enables users to easily move, copy, or delete data. The following are some key concepts involved:
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ci* Drag operation: an operation that begins when a user selects a draggable component, continues when the user drags the component on the screen, and ends when the user releases the component on a droppable component.
8e41f4b71Sopenharmony_ci* Drag preview (background): a visual representation of the data being dragged. You can set it by using [CustomerBuilder](../reference/apis-arkui/arkui-ts/ts-types.md#custombuilder8) or [DragItemInfo](../reference/apis-arkui/arkui-ts/ts-universal-events-drag-drop.md#dragiteminfo) of [onDragStart](../reference/apis-arkui/arkui-ts/ts-universal-events-drag-drop.md#ondragstart), or by using the universal attribute [dragPreview](../reference/apis-arkui/arkui-ts/ts-universal-attributes-drag-drop.md#dragpreview11).
9e41f4b71Sopenharmony_ci* Drag data: data being dragged; encapsulated using the UDMF API [UnifiedData](../reference/apis-arkdata/js-apis-data-unifiedDataChannel.md#unifieddata).
10e41f4b71Sopenharmony_ci* Drag source: component that initiates the drag operation and provides data.
11e41f4b71Sopenharmony_ci* Drop target: component that can receive and process drag data.
12e41f4b71Sopenharmony_ci* Drag point: position where the mouse device or finger has in contact with the screen. It is used to determine whether data enters a drop target.
13e41f4b71Sopenharmony_ci
14e41f4b71Sopenharmony_ci## Drag Process
15e41f4b71Sopenharmony_ci
16e41f4b71Sopenharmony_ci### ​Gesture-based Drag Operation
17e41f4b71Sopenharmony_ci
18e41f4b71Sopenharmony_ci​If a drag operation is initiated by a gesture, the framework checks whether the current component is draggable. For draggable components ([Search](../reference/apis-arkui/arkui-ts/ts-basic-components-search.md), [TextInput](../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md), [TextArea](../reference/apis-arkui/arkui-ts/ts-basic-components-textarea.md), [RichEditor](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md), [Text](../reference/apis-arkui/arkui-ts/ts-basic-components-text.md), [Image](../reference/apis-arkui/arkui-ts/ts-basic-components-image.md), <!--Del-->[FormComponent](../reference/apis-arkui/arkui-ts/ts-basic-components-formcomponent-sys.md), <!--DelEnd-->[Hyperlink](../reference/apis-arkui/arkui-ts/ts-container-hyperlink.md)), the framework checks whether their [draggable](../reference/apis-arkui/arkui-ts/ts-universal-attributes-drag-drop.md#draggable) attribute is set to **true** (this attribute is true by default if layered parameters are used); for other components, the framework checks whether the **onDragStart** callback is set. If the attribute or callback is set as required, the framework starts dragging once a user has long pressed the component for 500 ms or longer, and displays a drag preview once the user has long pressed the component for 800 ms.
19e41f4b71Sopenharmony_ci
20e41f4b71Sopenharmony_ciBelow you can see the drag process initiated by a gesture (finger or stylus).
21e41f4b71Sopenharmony_ci
22e41f4b71Sopenharmony_ci![en-us_image_0000001562820825](figures/en-us_image_0000001562820825.png)
23e41f4b71Sopenharmony_ci
24e41f4b71Sopenharmony_ci### ​Mouse-based Drag Operation
25e41f4b71Sopenharmony_ci
26e41f4b71Sopenharmony_ciWhen a mouse device is used as the pointer, the framework starts dragging once the draggable component has been moved with the left mouse button by more than 1 vp.
27e41f4b71Sopenharmony_ci
28e41f4b71Sopenharmony_ciA drag and drop can occur in a single application, or start in one application and end in another. The following callback events are provided for you to detect the dragging status and intervene in the default dragging behavior of the system.
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ci| Callback Event| Description|
31e41f4b71Sopenharmony_ci| ---------------- | ------------------------|
32e41f4b71Sopenharmony_ci| onDragStart | Triggered when a draggable component is dragged.<br>You can use this callback to detect the initiation of dragging behavior. You can also set the drag data and drag preview in this callback. To avoid extra performance overhead, it is recommended that the drag preview be returned in the mode of **pixelmap**, instead of **customBuilder**.|
33e41f4b71Sopenharmony_ci| onDragEnter | Triggered when a dragged item enters the boundaries of the component. This callback is called only when the component listens for the [onDrop](../reference/apis-arkui/arkui-ts/ts-universal-events-drag-drop.md#ondrop) event.|
34e41f4b71Sopenharmony_ci| onDragMove| Triggered when the dragged item moves in the boundaries of the component. This callback is called only when the component listens for the **onDrop** event.<br>During the movement, the **setResult** API in [DragEvent](../reference/apis-arkui/arkui-ts/ts-universal-events-drag-drop.md#dragevent) can be used to affect the system appearance in some scenarios.<br>1. Set **DragResult.DROP\_ENABLED**.<br>2. Set **DragResult.DROP\_DISABLED**.|
35e41f4b71Sopenharmony_ci| onDragLeave | Triggered when the dragged item leaves the boundaries of the component. This callback is called only when the component listens for the **onDrop** event.<br>By default, the **onDragLeave** callback is not called in the following cases:<br>1. An item in a parent component is dragged to one of its child components.<br>2. The layout of the drop target component overlaps that of the drag source component.<br>Since API version 12, the [setDragEventStrictReportingEnabled](../reference/apis-arkui/js-apis-arkui-UIContext.md#setdrageventstrictreportingenabled12) API in [UIContext](../reference/apis-arkui/js-apis-arkui-UIContext.md) can be used to trigger the **onDragLeave** event in a strict fashion.|
36e41f4b71Sopenharmony_ci| onDrop | Triggered when the dragged item is dropped on the component. The dragging result must be set in this callback through the **setResult** API in **DragEvent**. Otherwise, the **getResult** API in the **onDragEnd** method of the drag source component only returns the default result **DragResult.DRAG\_FAILED**.<br>This callback is where you can intervene in the default drop processing behavior. The system preferentially executes the **onDrop** callback and processes the drag data based on the **setResult** method in the callback function.<br>1. If **DragResult.DRAG\_SUCCESSFUL** is set, you need to process the data on your own; the system does not process the data.<br>2. If **DragResult.DRAG\_FAILED** is set, the system does not process the data.<br>3. If **DragResult.DRAG\_CANCELED** is set, the system does not process the data.<br>4. Setting **DragResult.DROP\_ENABLED** or **DragResult.DROP\_DISABLED** will be ignored, producing the same effect as **DragResult.DRAG\_FAILED**.|
37e41f4b71Sopenharmony_ci| onDragEnd | Triggered when dragging of the component ends.|
38e41f4b71Sopenharmony_ci| onPreDrag | Triggered when the component enters a state prior to a drop and drop operation.<br>You can use this callback to listen for the value of [PreDragStatus](../reference/apis-arkui/arkui-ts/ts-universal-events-drag-drop.md#predragstatus12) to prepare corresponding data.<br>1. **ACTION\_DETECTING\_STATUS**: A drag gesture is being detected. (Triggered when the component is long pressed for 50 ms.)<br>2. **READY\_TO\_TRIGGER\_DRAG\_ACTION**: The component is ready to be dragged. (Triggered when the component is long pressed for 500 ms.)<br>3. **PREVIEW\_LIFT\_STARTED**: A lift animation is started. (Triggered when the component is long pressed for 800 ms.)<br>4. **PREVIEW\_LIFT\_FINISHED**: A lift animation is finished. (Triggered at the completion of the lift animation.)<br>5. **PREVIEW\_LANDING\_STARTED**: A drop animation is started. (Triggered when the drop animation starts.)<br>6. **PREVIEW\_LANDING\_FINISHED**: A drop animation is finished. (Triggered when the drop animation ends.)<br>7. **ACTION\_CANCELED\_BEFORE\_DRAG**: A drop animation is terminated. (Triggered when the finger is lifted off the screen after the component enters the **READY\_TO\_TRIGGER\_DRAG\_ACTION** state.)|
39e41f4b71Sopenharmony_ci
40e41f4b71Sopenharmony_ciFor more usage, see [Drag Event](../reference/apis-arkui/arkui-ts/ts-universal-events-drag-drop.md)
41e41f4b71Sopenharmony_ci
42e41f4b71Sopenharmony_ci## Drag Preview
43e41f4b71Sopenharmony_ci
44e41f4b71Sopenharmony_ciThe drag preview is an image displayed during the drag and drop operation. It is a visual representation of the drag data, not the component itself. You can set it to any supported image that you want to display to users. The **customBuilder** or **pixelmap** object returned by the **onDragStart** callback can be used to set the drag preview – snapshot of the component by default – displayed during dragging and moving. The **customBuilder** or **pixelmap** object set by the **dragpreview** attribute can be used to set the drag preview – snapshot of the component by default – during a lift animation and dragging.
45e41f4b71Sopenharmony_ci
46e41f4b71Sopenharmony_ciYou can set the opacity, rounded corners, shadow, and blur for the drag preview. For details, see [Drag and Drop Control](../reference/apis-arkui/arkui-ts/ts-universal-attributes-drag-drop.md).
47e41f4b71Sopenharmony_ci
48e41f4b71Sopenharmony_ci**Constraints**:
49e41f4b71Sopenharmony_ci
50e41f4b71Sopenharmony_ci* For a container component, if the internal content exceeds the range of the container component due to **position**, **offset**, and other settings, the component snapshot does not capture the content beyond the range. To show the out-of-range content, you can expand the container scope or customize the container.
51e41f4b71Sopenharmony_ci* Regardless of how the component snapshot is captured, using a custom builder or the default mode, the snapshot does not support the transform APIs, such as [scale](../reference/apis-arkui/arkui-ts/ts-universal-attributes-transformation.md#scale) and [rotate](../reference/apis-arkui/arkui-ts/ts-universal-attributes-transformation.md#rotate).
52e41f4b71Sopenharmony_ci
53e41f4b71Sopenharmony_ci## How to Develop
54e41f4b71Sopenharmony_ci
55e41f4b71Sopenharmony_ci### General Drag and Drop Adaptation
56e41f4b71Sopenharmony_ci
57e41f4b71Sopenharmony_ciThe following uses the [Image](../reference/apis-arkui/arkui-ts/ts-basic-components-image.md) component as an example to describe the basic procedure for drag and drop development and the precautions to be taken during development.
58e41f4b71Sopenharmony_ci
59e41f4b71Sopenharmony_ci1. Make the component draggable.
60e41f4b71Sopenharmony_ci
61e41f4b71Sopenharmony_ci* Set the **draggable** attribute to **true** and set the **onDragStart** callback function. In the callback function, you can use UDMF to set the drag data and return the custom drag preview.
62e41f4b71Sopenharmony_ci
63e41f4b71Sopenharmony_ci    ```ts
64e41f4b71Sopenharmony_ci    import { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData';
65e41f4b71Sopenharmony_ci
66e41f4b71Sopenharmony_ci    Image($r('app.media.app_icon'))
67e41f4b71Sopenharmony_ci        .width(100)
68e41f4b71Sopenharmony_ci        .height(100)
69e41f4b71Sopenharmony_ci        .draggable(true)
70e41f4b71Sopenharmony_ci        .onDragStart((event) => {
71e41f4b71Sopenharmony_ci            let data: unifiedDataChannel.Image = new unifiedDataChannel.Image();
72e41f4b71Sopenharmony_ci            data.imageUri = 'common/pic/img.png';
73e41f4b71Sopenharmony_ci            let unifiedData = new unifiedDataChannel.UnifiedData(data);
74e41f4b71Sopenharmony_ci            event.setData(unifiedData);
75e41f4b71Sopenharmony_ci
76e41f4b71Sopenharmony_ci            let dragItemInfo: DragItemInfo = {
77e41f4b71Sopenharmony_ci            pixelMap: this.pixmap,
78e41f4b71Sopenharmony_ci            extraInfo: "this is extraInfo",
79e41f4b71Sopenharmony_ci            };
80e41f4b71Sopenharmony_ci            // The custom drag preview is returned in onDragStart.
81e41f4b71Sopenharmony_ci            return dragItemInfo;
82e41f4b71Sopenharmony_ci        })
83e41f4b71Sopenharmony_ci    ```
84e41f4b71Sopenharmony_ci
85e41f4b71Sopenharmony_ci* The gesture-based drag operation is initiated by a long press gesture bound at the underlying layer. If a long press gesture is also bound to the dragged component, gesture conflict will occur, resulting in dragging to fail. To avoid such an issue, you can use parallel gestures.
86e41f4b71Sopenharmony_ci
87e41f4b71Sopenharmony_ci    ```ts
88e41f4b71Sopenharmony_ci    .parallelGesture(LongPressGesture().onAction(() => {
89e41f4b71Sopenharmony_ci       promptAction.showToast({ duration: 100, message: 'Long press gesture trigger' });
90e41f4b71Sopenharmony_ci    }))
91e41f4b71Sopenharmony_ci    ```
92e41f4b71Sopenharmony_ci
93e41f4b71Sopenharmony_ci2. Customize the drag preview.
94e41f4b71Sopenharmony_ci   
95e41f4b71Sopenharmony_ci  * Prepare the pixel map for the custom drag preview within the callback triggered by [onPreDrag](../reference/apis-arkui/arkui-ts/ts-universal-events-drag-drop.md#onpredrag12) after a long press of 50 ms.
96e41f4b71Sopenharmony_ci   
97e41f4b71Sopenharmony_ci    ```ts
98e41f4b71Sopenharmony_ci    .onPreDrag((status: PreDragStatus) => {
99e41f4b71Sopenharmony_ci        if (preDragStatus == PreDragStatus.ACTION_DETECTING_STATUS) {
100e41f4b71Sopenharmony_ci            this.getComponentSnapshot();
101e41f4b71Sopenharmony_ci        }
102e41f4b71Sopenharmony_ci    })
103e41f4b71Sopenharmony_ci    ```
104e41f4b71Sopenharmony_ci   
105e41f4b71Sopenharmony_ci   * Generate the specific pixel map by calling [componentSnapshot.createFromBuilder](../reference/apis-arkui/js-apis-arkui-componentSnapshot.md#componentsnapshotcreatefrombuilder).
106e41f4b71Sopenharmony_ci
107e41f4b71Sopenharmony_ci      ```ts
108e41f4b71Sopenharmony_ci      @Builder
109e41f4b71Sopenharmony_ci      pixelMapBuilder() {
110e41f4b71Sopenharmony_ci          Column() {
111e41f4b71Sopenharmony_ci            Image($r('app.media.startIcon'))
112e41f4b71Sopenharmony_ci              .width(120)
113e41f4b71Sopenharmony_ci              .height(120)
114e41f4b71Sopenharmony_ci              .backgroundColor(Color.Yellow)
115e41f4b71Sopenharmony_ci          }
116e41f4b71Sopenharmony_ci        }
117e41f4b71Sopenharmony_ci        private getComponentSnapshot(): void {
118e41f4b71Sopenharmony_ci        componentSnapshot.createFromBuilder(()=>{this.pixelMapBuilder()},
119e41f4b71Sopenharmony_ci        (error: Error, pixmap: image.PixelMap) => {
120e41f4b71Sopenharmony_ci            if(error){
121e41f4b71Sopenharmony_ci              console.log("error: " + JSON.stringify(error))
122e41f4b71Sopenharmony_ci              return;
123e41f4b71Sopenharmony_ci            }
124e41f4b71Sopenharmony_ci            this.pixmap = pixmap;
125e41f4b71Sopenharmony_ci        })
126e41f4b71Sopenharmony_ci      }
127e41f4b71Sopenharmony_ci      ```
128e41f4b71Sopenharmony_ci
129e41f4b71Sopenharmony_ci3. To strictly execute the [onDragLeave](../reference/apis-arkui/arkui-ts/ts-universal-events-drag-drop.md#ondragleave) event, use the [setDragEventStrictReportingEnabled](../reference/apis-arkui/js-apis-arkui-UIContext.md#setdrageventstrictreportingenabled12) API.
130e41f4b71Sopenharmony_ci
131e41f4b71Sopenharmony_ci    ```ts
132e41f4b71Sopenharmony_ci    import { UIAbility } from '@kit.AbilityKit';
133e41f4b71Sopenharmony_ci    import { window, UIContext } from '@kit.ArkUI';
134e41f4b71Sopenharmony_ci
135e41f4b71Sopenharmony_ci    export default class EntryAbility extends UIAbility {
136e41f4b71Sopenharmony_ci      onWindowStageCreate(windowStage: window.WindowStage): void {
137e41f4b71Sopenharmony_ci        windowStage.loadContent('pages/Index', (err, data) => {
138e41f4b71Sopenharmony_ci          if (err.code) {
139e41f4b71Sopenharmony_ci            return;
140e41f4b71Sopenharmony_ci          }
141e41f4b71Sopenharmony_ci          windowStage.getMainWindow((err, data) => {
142e41f4b71Sopenharmony_ci            if (err.code) {
143e41f4b71Sopenharmony_ci              return;
144e41f4b71Sopenharmony_ci            }
145e41f4b71Sopenharmony_ci            let windowClass: window.Window = data;
146e41f4b71Sopenharmony_ci            let uiContext: UIContext = windowClass.getUIContext();
147e41f4b71Sopenharmony_ci            uiContext.getDragController().setDragEventStrictReportingEnabled(true);
148e41f4b71Sopenharmony_ci          });
149e41f4b71Sopenharmony_ci        });
150e41f4b71Sopenharmony_ci      }
151e41f4b71Sopenharmony_ci    }
152e41f4b71Sopenharmony_ci    ```
153e41f4b71Sopenharmony_ci
154e41f4b71Sopenharmony_ci4. Set the badge displayed during dragging.
155e41f4b71Sopenharmony_ci
156e41f4b71Sopenharmony_ci* You can set [allowDrop](../reference/apis-arkui/arkui-ts/ts-universal-attributes-drag-drop.md#allowdrop) to define the allowed data types for dropping to affect the badge display. The COPY badge is displayed when the drag data matches the allowed data types, the FORBIDDEN badge when it does not, and the MOVE badge if **allowDrop** is not set. The following example allows only data of HYPERLINK and PLAIN_TEXT types defined in UnifiedData.
157e41f4b71Sopenharmony_ci
158e41f4b71Sopenharmony_ci    ```ts
159e41f4b71Sopenharmony_ci    .allowDrop([uniformTypeDescriptor.UniformDataType.HYPERLINK, uniformTypeDescriptor.UniformDataType.PLAIN_TEXT])
160e41f4b71Sopenharmony_ci    ```
161e41f4b71Sopenharmony_ci
162e41f4b71Sopenharmony_ci* If the **onDrop** callback is implemented, you can control the badge display by setting [DragResult](../reference/apis-arkui/arkui-ts/ts-universal-events-drag-drop.md#dragresult10) to **DROP\_ENABLED** in **onDragMove** and setting [DragBehavior](../reference/apis-arkui/arkui-ts/ts-universal-events-drag-drop.md#dragbehavior10) to **COPY** or **MOVE**. The following code forces the badge to display **MOVE** during a drag operation:
163e41f4b71Sopenharmony_ci
164e41f4b71Sopenharmony_ci    ```ts
165e41f4b71Sopenharmony_ci    .onDragMove((event) => {
166e41f4b71Sopenharmony_ci        event.setResult(DragResult.DROP_ENABLED);
167e41f4b71Sopenharmony_ci        event.dragBehavior = DragBehavior.MOVE;
168e41f4b71Sopenharmony_ci    })
169e41f4b71Sopenharmony_ci    ```
170e41f4b71Sopenharmony_ci
171e41f4b71Sopenharmony_ci5. Receive drag data.
172e41f4b71Sopenharmony_ci
173e41f4b71Sopenharmony_ci* Set the **onDrop** callback to handle the drag data and determine the drag result.
174e41f4b71Sopenharmony_ci
175e41f4b71Sopenharmony_ci    ```ts
176e41f4b71Sopenharmony_ci    .onDrop((dragEvent?: DragEvent) => {
177e41f4b71Sopenharmony_ci        // Obtain the drag data.
178e41f4b71Sopenharmony_ci        this.getDataFromUdmf((dragEvent as DragEvent), (event: DragEvent) => {
179e41f4b71Sopenharmony_ci        let records: Array<unifiedDataChannel.UnifiedRecord> = event.getData().getRecords();
180e41f4b71Sopenharmony_ci        let rect: Rectangle = event.getPreviewRect();
181e41f4b71Sopenharmony_ci        this.imageWidth = Number(rect.width);
182e41f4b71Sopenharmony_ci        this.imageHeight = Number(rect.height);
183e41f4b71Sopenharmony_ci        this.targetImage = (records[0] as unifiedDataChannel.Image).imageUri;
184e41f4b71Sopenharmony_ci        this.imgState = Visibility.None;
185e41f4b71Sopenharmony_ci        // Explicitly set the result to successful, and then pass this value to onDragEnd of the drag source.
186e41f4b71Sopenharmony_ci        event.setResult(DragResult.DRAG_SUCCESSFUL);
187e41f4b71Sopenharmony_ci    })
188e41f4b71Sopenharmony_ci    ```
189e41f4b71Sopenharmony_ci
190e41f4b71Sopenharmony_ci* Data transfer is managed by UDMF, which may experience latency with large data volumes. Therefore, you are advised to implement a retry mechanism with a 1500 ms delay after the initial data acquisition fails.
191e41f4b71Sopenharmony_ci
192e41f4b71Sopenharmony_ci    ```ts
193e41f4b71Sopenharmony_ci    getDataFromUdmfRetry(event: DragEvent, callback: (data: DragEvent) => void) {
194e41f4b71Sopenharmony_ci       try {
195e41f4b71Sopenharmony_ci         let data: UnifiedData = event.getData();
196e41f4b71Sopenharmony_ci         if (!data) {
197e41f4b71Sopenharmony_ci           return false;
198e41f4b71Sopenharmony_ci         }
199e41f4b71Sopenharmony_ci         let records: Array<unifiedDataChannel.UnifiedRecord> = data.getRecords();
200e41f4b71Sopenharmony_ci         if (!records || records.length <= 0) {
201e41f4b71Sopenharmony_ci           return false;
202e41f4b71Sopenharmony_ci         }
203e41f4b71Sopenharmony_ci         callback(event);
204e41f4b71Sopenharmony_ci         return true;
205e41f4b71Sopenharmony_ci       } catch (e) {
206e41f4b71Sopenharmony_ci         console.log("getData failed, code: " + (e as BusinessError).code + ", message: " + (e as BusinessError).message);
207e41f4b71Sopenharmony_ci         return false;
208e41f4b71Sopenharmony_ci       }
209e41f4b71Sopenharmony_ci    }
210e41f4b71Sopenharmony_ci
211e41f4b71Sopenharmony_ci    getDataFromUdmf(event: DragEvent, callback: (data: DragEvent) => void) {
212e41f4b71Sopenharmony_ci      if (this.getDataFromUdmfRetry(event, callback)) {
213e41f4b71Sopenharmony_ci        return;
214e41f4b71Sopenharmony_ci      }
215e41f4b71Sopenharmony_ci      setTimeout(() => {
216e41f4b71Sopenharmony_ci        this.getDataFromUdmfRetry(event, callback);
217e41f4b71Sopenharmony_ci      }, 1500);
218e41f4b71Sopenharmony_ci    }
219e41f4b71Sopenharmony_ci    ```
220e41f4b71Sopenharmony_ci
221e41f4b71Sopenharmony_ci6. The drag initiator can detect the result of the drag operation by setting the **onDragEnd** callback.
222e41f4b71Sopenharmony_ci
223e41f4b71Sopenharmony_ci    ```ts
224e41f4b71Sopenharmony_ci    import { promptAction } from '@kit.ArkUI';
225e41f4b71Sopenharmony_ci
226e41f4b71Sopenharmony_ci    .onDragEnd((event) => {
227e41f4b71Sopenharmony_ci        // The result value obtained from onDragEnd is set in onDrop of the drop target.
228e41f4b71Sopenharmony_ci      if (event.getResult() === DragResult.DRAG_SUCCESSFUL) {
229e41f4b71Sopenharmony_ci        promptAction.showToast({ duration: 100, message: 'Drag Success' });
230e41f4b71Sopenharmony_ci      } else if (event.getResult() === DragResult.DRAG_FAILED) {
231e41f4b71Sopenharmony_ci        promptAction.showToast({ duration: 100, message: 'Drag failed' });
232e41f4b71Sopenharmony_ci      }
233e41f4b71Sopenharmony_ci    })
234e41f4b71Sopenharmony_ci    ```
235e41f4b71Sopenharmony_ci
236e41f4b71Sopenharmony_ci### Multi-Select Drag and Drop Adaptation
237e41f4b71Sopenharmony_ci
238e41f4b71Sopenharmony_ciSince API version 12, the [Grid](../reference/apis-arkui/arkui-ts/ts-container-grid.md) and [List](../reference/apis-arkui/arkui-ts/ts-container-list.md) components, specifically the **GridItem** and **ListItem** components within them, support multi-select drag and drop, currently only accessible through the **onDragStart** API. The following uses **Grid** as an example to describe the basic procedure for multi-select drag and drop development and key considrations during development.
239e41f4b71Sopenharmony_ci
240e41f4b71Sopenharmony_ci1. Enable multi-select drag and drop.
241e41f4b71Sopenharmony_ci
242e41f4b71Sopenharmony_ci* Create **GridItem** child components and bind the **onDragStart** callback to them. In addition, set the **GridItem** components to be selectable.
243e41f4b71Sopenharmony_ci
244e41f4b71Sopenharmony_ci    ```ts
245e41f4b71Sopenharmony_ci    Grid() {
246e41f4b71Sopenharmony_ci      ForEach(this.numbers, (idx: number) => {
247e41f4b71Sopenharmony_ci        GridItem() {
248e41f4b71Sopenharmony_ci          Column()
249e41f4b71Sopenharmony_ci            .backgroundColor(this.colors[idx % 9])
250e41f4b71Sopenharmony_ci            .width(50)
251e41f4b71Sopenharmony_ci            .height(50)
252e41f4b71Sopenharmony_ci            .opacity(1.0)
253e41f4b71Sopenharmony_ci            .id('grid'+idx)
254e41f4b71Sopenharmony_ci        }
255e41f4b71Sopenharmony_ci        .onDragStart(()=>{})
256e41f4b71Sopenharmony_ci        .selectable(true)
257e41f4b71Sopenharmony_ci      }, (idx: string) => idx)
258e41f4b71Sopenharmony_ci    }
259e41f4b71Sopenharmony_ci    ```
260e41f4b71Sopenharmony_ci
261e41f4b71Sopenharmony_ci* Multi-select drag and drop is disabled by default. To enable it, set **isMultiSelectionEnabled** to **true** in the **DragInteractionOptions** parameter of the [dragPreviewOptions](../reference/apis-arkui/arkui-ts/ts-universal-attributes-drag-drop.md#dragpreviewoptions11) API. **DragInteractionOptions** also has the **defaultAnimationBeforeLifting** parameter, which, when set to **true**, applies a default scaling down animation as the lift animation for the component.
262e41f4b71Sopenharmony_ci
263e41f4b71Sopenharmony_ci    ```ts
264e41f4b71Sopenharmony_ci    .dragPreviewOptions({isMultiSelectionEnabled:true,defaultAnimationBeforeLifting:true})
265e41f4b71Sopenharmony_ci    ```
266e41f4b71Sopenharmony_ci
267e41f4b71Sopenharmony_ci* To maintain the selected state, set the **selected** attribute of the **GridItem** child component to **true**. For example, use [onClick](../reference/apis-arkui/arkui-ts/ts-universal-events-click.md#onclick) to set a specific component to the selected state.
268e41f4b71Sopenharmony_ci
269e41f4b71Sopenharmony_ci    ```ts
270e41f4b71Sopenharmony_ci    .selected(this.isSelectedGrid[idx])
271e41f4b71Sopenharmony_ci    .onClick(()=>{
272e41f4b71Sopenharmony_ci        this.isSelectedGrid[idx] = !this.isSelectedGrid[idx]
273e41f4b71Sopenharmony_ci    })
274e41f4b71Sopenharmony_ci    ```
275e41f4b71Sopenharmony_ci
276e41f4b71Sopenharmony_ci2. Optimize the multi-select drag and drop performance.
277e41f4b71Sopenharmony_ci
278e41f4b71Sopenharmony_ci* In multi-select drag and drop scenarios, there is a clustering animation effect when multiple items are selected. This effect captures a snapshot of the selected components currently displayed on the screen, which can lead to high performance costs if there are too many selected components. To save on performance, multi-select drag and drop supports obtaining a snapshot from **dragPreview** to use as the basis for the clustering animation.
279e41f4b71Sopenharmony_ci
280e41f4b71Sopenharmony_ci    ```ts
281e41f4b71Sopenharmony_ci    .dragPreview({
282e41f4b71Sopenharmony_ci        pixelMap:this.pixmap
283e41f4b71Sopenharmony_ci    })
284e41f4b71Sopenharmony_ci    ```
285e41f4b71Sopenharmony_ci
286e41f4b71Sopenharmony_ci* You can obtain snapshots of a component by calling the **get** method of **componentSnapshot** when the component is selected. The following shows how to use the component ID to obtain the snapshot.
287e41f4b71Sopenharmony_ci
288e41f4b71Sopenharmony_ci    ```ts
289e41f4b71Sopenharmony_ci    @State previewData: DragItemInfo[] = []
290e41f4b71Sopenharmony_ci    @State isSelectedGrid: boolean[] = []
291e41f4b71Sopenharmony_ci    .onClick(()=>{
292e41f4b71Sopenharmony_ci        this.isSelectedGrid[idx] = !this.isSelectedGrid[idx]
293e41f4b71Sopenharmony_ci        if (this.isSelectedGrid[idx]) {
294e41f4b71Sopenharmony_ci            let gridItemName = 'grid' + idx
295e41f4b71Sopenharmony_ci            componentSnapshot.get(gridItemName, (error: Error, pixmap: image.PixelMap)=>{
296e41f4b71Sopenharmony_ci                this.pixmap = pixmap
297e41f4b71Sopenharmony_ci                this.previewData[idx] = {
298e41f4b71Sopenharmony_ci                    pixelMap:this.pixmap
299e41f4b71Sopenharmony_ci                }
300e41f4b71Sopenharmony_ci            })
301e41f4b71Sopenharmony_ci        }
302e41f4b71Sopenharmony_ci    })
303e41f4b71Sopenharmony_ci    ```
304e41f4b71Sopenharmony_ci
305e41f4b71Sopenharmony_ci3. Set the multi-select display effects.
306e41f4b71Sopenharmony_ci
307e41f4b71Sopenharmony_ci    Use **stateStyles** to set display effects for selected and unselected states for easy distinction.
308e41f4b71Sopenharmony_ci
309e41f4b71Sopenharmony_ci    ```ts
310e41f4b71Sopenharmony_ci    @Styles
311e41f4b71Sopenharmony_ci    normalStyles(): void{
312e41f4b71Sopenharmony_ci      .opacity(1.0)
313e41f4b71Sopenharmony_ci    }
314e41f4b71Sopenharmony_ci
315e41f4b71Sopenharmony_ci    @Styles
316e41f4b71Sopenharmony_ci    selectStyles(): void{
317e41f4b71Sopenharmony_ci      .opacity(0.4)
318e41f4b71Sopenharmony_ci    }
319e41f4b71Sopenharmony_ci
320e41f4b71Sopenharmony_ci    .stateStyles({
321e41f4b71Sopenharmony_ci      normal : this.normalStyles,
322e41f4b71Sopenharmony_ci      selected: this.selectStyles
323e41f4b71Sopenharmony_ci    })
324e41f4b71Sopenharmony_ci    ```
325e41f4b71Sopenharmony_ci
326e41f4b71Sopenharmony_ci4. Adapt the number badge.
327e41f4b71Sopenharmony_ci
328e41f4b71Sopenharmony_ci    Configure the number badge for multi-select drag and drop using the **numberBadge** parameter in **dragPreviewOptions**, adjusting it based on the number of selected items.
329e41f4b71Sopenharmony_ci
330e41f4b71Sopenharmony_ci    ```ts
331e41f4b71Sopenharmony_ci    @State numberBadge: number = 0;
332e41f4b71Sopenharmony_ci
333e41f4b71Sopenharmony_ci    .onClick(()=>{
334e41f4b71Sopenharmony_ci        this.isSelectedGrid[idx] = !this.isSelectedGrid[idx]
335e41f4b71Sopenharmony_ci        if (this.isSelectedGrid[idx]) {
336e41f4b71Sopenharmony_ci          this.numberBadge++;
337e41f4b71Sopenharmony_ci        } else {
338e41f4b71Sopenharmony_ci          this.numberBadge--;
339e41f4b71Sopenharmony_ci      }
340e41f4b71Sopenharmony_ci    })
341e41f4b71Sopenharmony_ci    // Set the numberBadge parameter in dragPreviewOptions for the number badge in multi-select scenarios.
342e41f4b71Sopenharmony_ci    .dragPreviewOptions({numberBadge: this.numberBadge})
343e41f4b71Sopenharmony_ci    ```
344e41f4b71Sopenharmony_ci
345e41f4b71Sopenharmony_ci## Example
346e41f4b71Sopenharmony_ci
347e41f4b71Sopenharmony_ci### General Drag and Drop Adaptation Case
348e41f4b71Sopenharmony_ci
349e41f4b71Sopenharmony_ci```ts
350e41f4b71Sopenharmony_ciimport { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData';
351e41f4b71Sopenharmony_ciimport { promptAction, componentSnapshot } from '@kit.ArkUI';
352e41f4b71Sopenharmony_ciimport { BusinessError } from '@kit.BasicServicesKit';
353e41f4b71Sopenharmony_ciimport { image } from '@kit.ImageKit';
354e41f4b71Sopenharmony_ci
355e41f4b71Sopenharmony_ci@Entry
356e41f4b71Sopenharmony_ci@Component
357e41f4b71Sopenharmony_cistruct Index {
358e41f4b71Sopenharmony_ci  @State targetImage: string = '';
359e41f4b71Sopenharmony_ci  @State imageWidth: number = 100;
360e41f4b71Sopenharmony_ci  @State imageHeight: number = 100;
361e41f4b71Sopenharmony_ci  @State imgState: Visibility = Visibility.Visible;
362e41f4b71Sopenharmony_ci  @State pixmap: image.PixelMap|undefined = undefined
363e41f4b71Sopenharmony_ci
364e41f4b71Sopenharmony_ci  @Builder
365e41f4b71Sopenharmony_ci  pixelMapBuilder() {
366e41f4b71Sopenharmony_ci    Column() {
367e41f4b71Sopenharmony_ci      Image($r('app.media.startIcon'))
368e41f4b71Sopenharmony_ci        .width(120)
369e41f4b71Sopenharmony_ci        .height(120)
370e41f4b71Sopenharmony_ci        .backgroundColor(Color.Yellow)
371e41f4b71Sopenharmony_ci    }
372e41f4b71Sopenharmony_ci  }
373e41f4b71Sopenharmony_ci
374e41f4b71Sopenharmony_ci  getDataFromUdmfRetry(event: DragEvent, callback: (data: DragEvent) => void) {
375e41f4b71Sopenharmony_ci    try {
376e41f4b71Sopenharmony_ci      let data: UnifiedData = event.getData();
377e41f4b71Sopenharmony_ci      if (!data) {
378e41f4b71Sopenharmony_ci        return false;
379e41f4b71Sopenharmony_ci      }
380e41f4b71Sopenharmony_ci      let records: Array<unifiedDataChannel.UnifiedRecord> = data.getRecords();
381e41f4b71Sopenharmony_ci      if (!records || records.length <= 0) {
382e41f4b71Sopenharmony_ci        return false;
383e41f4b71Sopenharmony_ci      }
384e41f4b71Sopenharmony_ci      callback(event);
385e41f4b71Sopenharmony_ci      return true;
386e41f4b71Sopenharmony_ci    } catch (e) {
387e41f4b71Sopenharmony_ci      console.log("getData failed, code: " + (e as BusinessError).code + ", message: " + (e as BusinessError).message);
388e41f4b71Sopenharmony_ci      return false;
389e41f4b71Sopenharmony_ci    }
390e41f4b71Sopenharmony_ci  }
391e41f4b71Sopenharmony_ci  // Obtain UDMF data with a retry mechanism of 1500 ms if the initial attempt fails.
392e41f4b71Sopenharmony_ci  getDataFromUdmf(event: DragEvent, callback: (data: DragEvent) => void) {
393e41f4b71Sopenharmony_ci    if (this.getDataFromUdmfRetry(event, callback)) {
394e41f4b71Sopenharmony_ci      return;
395e41f4b71Sopenharmony_ci    }
396e41f4b71Sopenharmony_ci    setTimeout(() => {
397e41f4b71Sopenharmony_ci      this.getDataFromUdmfRetry(event, callback);
398e41f4b71Sopenharmony_ci    }, 1500);
399e41f4b71Sopenharmony_ci  }
400e41f4b71Sopenharmony_ci  // Use the createFromBuilder API of componentSnapshot to capture a snapshot of a custom builder.
401e41f4b71Sopenharmony_ci  private getComponentSnapshot(): void {
402e41f4b71Sopenharmony_ci    componentSnapshot.createFromBuilder(()=>{this.pixelMapBuilder()},
403e41f4b71Sopenharmony_ci      (error: Error, pixmap: image.PixelMap) => {
404e41f4b71Sopenharmony_ci        if(error){
405e41f4b71Sopenharmony_ci          console.log("error: " + JSON.stringify(error))
406e41f4b71Sopenharmony_ci          return;
407e41f4b71Sopenharmony_ci        }
408e41f4b71Sopenharmony_ci        this.pixmap = pixmap;
409e41f4b71Sopenharmony_ci      })
410e41f4b71Sopenharmony_ci  }
411e41f4b71Sopenharmony_ci  // Prepare a custom screenshot pixel map after a 50 ms long press is detected.
412e41f4b71Sopenharmony_ci  private PreDragChange(preDragStatus: PreDragStatus): void {
413e41f4b71Sopenharmony_ci    if (preDragStatus == PreDragStatus.ACTION_DETECTING_STATUS) {
414e41f4b71Sopenharmony_ci      this.getComponentSnapshot();
415e41f4b71Sopenharmony_ci    }
416e41f4b71Sopenharmony_ci  }
417e41f4b71Sopenharmony_ci
418e41f4b71Sopenharmony_ci  build() {
419e41f4b71Sopenharmony_ci    Row() {
420e41f4b71Sopenharmony_ci      Column() {
421e41f4b71Sopenharmony_ci        Text('start Drag')
422e41f4b71Sopenharmony_ci          .fontSize(18)
423e41f4b71Sopenharmony_ci          .width('100%')
424e41f4b71Sopenharmony_ci          .height(40)
425e41f4b71Sopenharmony_ci          .margin(10)
426e41f4b71Sopenharmony_ci          .backgroundColor('#008888')
427e41f4b71Sopenharmony_ci        Row() {
428e41f4b71Sopenharmony_ci          Image($r('app.media.app_icon'))
429e41f4b71Sopenharmony_ci            .width(100)
430e41f4b71Sopenharmony_ci            .height(100)
431e41f4b71Sopenharmony_ci            .draggable(true)
432e41f4b71Sopenharmony_ci            .margin({ left: 15 })
433e41f4b71Sopenharmony_ci            .visibility(this.imgState)
434e41f4b71Sopenharmony_ci            // Bind a parallel gesture to trigger a custom long press gesture.
435e41f4b71Sopenharmony_ci            .parallelGesture(LongPressGesture().onAction(() => {
436e41f4b71Sopenharmony_ci              promptAction.showToast({ duration: 100, message: 'Long press gesture trigger' });
437e41f4b71Sopenharmony_ci            }))
438e41f4b71Sopenharmony_ci            .onDragStart((event) => {
439e41f4b71Sopenharmony_ci              let data: unifiedDataChannel.Image = new unifiedDataChannel.Image();
440e41f4b71Sopenharmony_ci              data.imageUri = 'common/pic/img.png';
441e41f4b71Sopenharmony_ci              let unifiedData = new unifiedDataChannel.UnifiedData(data);
442e41f4b71Sopenharmony_ci              event.setData(unifiedData);
443e41f4b71Sopenharmony_ci
444e41f4b71Sopenharmony_ci              let dragItemInfo: DragItemInfo = {
445e41f4b71Sopenharmony_ci                pixelMap: this.pixmap,
446e41f4b71Sopenharmony_ci                extraInfo: "this is extraInfo",
447e41f4b71Sopenharmony_ci              };
448e41f4b71Sopenharmony_ci              return dragItemInfo;
449e41f4b71Sopenharmony_ci            })
450e41f4b71Sopenharmony_ci              // Prepare a custom drag preview in advance.
451e41f4b71Sopenharmony_ci            .onPreDrag((status: PreDragStatus) => {
452e41f4b71Sopenharmony_ci              this.PreDragChange(status);
453e41f4b71Sopenharmony_ci            })
454e41f4b71Sopenharmony_ci            .onDragEnd((event) => {
455e41f4b71Sopenharmony_ci              // The result value obtained from onDragEnd is set in onDrop of the drop target.
456e41f4b71Sopenharmony_ci              if (event.getResult() === DragResult.DRAG_SUCCESSFUL) {
457e41f4b71Sopenharmony_ci                promptAction.showToast({ duration: 100, message: 'Drag Success' });
458e41f4b71Sopenharmony_ci              } else if (event.getResult() === DragResult.DRAG_FAILED) {
459e41f4b71Sopenharmony_ci                promptAction.showToast({ duration: 100, message: 'Drag failed' });
460e41f4b71Sopenharmony_ci              }
461e41f4b71Sopenharmony_ci            })
462e41f4b71Sopenharmony_ci        }
463e41f4b71Sopenharmony_ci
464e41f4b71Sopenharmony_ci        Text('Drag Target Area')
465e41f4b71Sopenharmony_ci          .fontSize(20)
466e41f4b71Sopenharmony_ci          .width('100%')
467e41f4b71Sopenharmony_ci          .height(40)
468e41f4b71Sopenharmony_ci          .margin(10)
469e41f4b71Sopenharmony_ci          .backgroundColor('#008888')
470e41f4b71Sopenharmony_ci        Row() {
471e41f4b71Sopenharmony_ci          Image(this.targetImage)
472e41f4b71Sopenharmony_ci            .width(this.imageWidth)
473e41f4b71Sopenharmony_ci            .height(this.imageHeight)
474e41f4b71Sopenharmony_ci            .draggable(true)
475e41f4b71Sopenharmony_ci            .margin({ left: 15 })
476e41f4b71Sopenharmony_ci            .border({ color: Color.Black, width: 1 })
477e41f4b71Sopenharmony_ci            // Set the drag behavior to MOVE, which means no badge is displayed.
478e41f4b71Sopenharmony_ci            .onDragMove((event) => {
479e41f4b71Sopenharmony_ci              event.setResult(DragResult.DROP_ENABLED)
480e41f4b71Sopenharmony_ci              event.dragBehavior = DragBehavior.MOVE
481e41f4b71Sopenharmony_ci            })
482e41f4b71Sopenharmony_ci            .allowDrop([uniformTypeDescriptor.UniformDataType.IMAGE])
483e41f4b71Sopenharmony_ci            .onDrop((dragEvent?: DragEvent) => {
484e41f4b71Sopenharmony_ci              // Obtain the drag data.
485e41f4b71Sopenharmony_ci              this.getDataFromUdmf((dragEvent as DragEvent), (event: DragEvent) => {
486e41f4b71Sopenharmony_ci                let records: Array<unifiedDataChannel.UnifiedRecord> = event.getData().getRecords();
487e41f4b71Sopenharmony_ci                let rect: Rectangle = event.getPreviewRect();
488e41f4b71Sopenharmony_ci                this.imageWidth = Number(rect.width);
489e41f4b71Sopenharmony_ci                this.imageHeight = Number(rect.height);
490e41f4b71Sopenharmony_ci                this.targetImage = (records[0] as unifiedDataChannel.Image).imageUri;
491e41f4b71Sopenharmony_ci                this.imgState = Visibility.None;
492e41f4b71Sopenharmony_ci                // Explicitly set the result to successful, and then pass this value to onDragEnd of the drag source.
493e41f4b71Sopenharmony_ci                event.setResult(DragResult.DRAG_SUCCESSFUL);
494e41f4b71Sopenharmony_ci              })
495e41f4b71Sopenharmony_ci            })
496e41f4b71Sopenharmony_ci        }
497e41f4b71Sopenharmony_ci      }
498e41f4b71Sopenharmony_ci      .width('100%')
499e41f4b71Sopenharmony_ci      .height('100%')
500e41f4b71Sopenharmony_ci    }
501e41f4b71Sopenharmony_ci    .height('100%')
502e41f4b71Sopenharmony_ci  }
503e41f4b71Sopenharmony_ci}
504e41f4b71Sopenharmony_ci
505e41f4b71Sopenharmony_ci```
506e41f4b71Sopenharmony_ci
507e41f4b71Sopenharmony_ci### Multi-Select Drag and Drop Adaptation Case
508e41f4b71Sopenharmony_ci
509e41f4b71Sopenharmony_ci```ts
510e41f4b71Sopenharmony_ciimport { componentSnapshot } from '@kit.ArkUI';
511e41f4b71Sopenharmony_ciimport { image } from '@kit.ImageKit';
512e41f4b71Sopenharmony_ci
513e41f4b71Sopenharmony_ci@Entry
514e41f4b71Sopenharmony_ci@Component
515e41f4b71Sopenharmony_cistruct GridEts {
516e41f4b71Sopenharmony_ci  @State pixmap: image.PixelMap|undefined = undefined
517e41f4b71Sopenharmony_ci  @State numbers: number[] = []
518e41f4b71Sopenharmony_ci  @State isSelectedGrid: boolean[] = []
519e41f4b71Sopenharmony_ci  @State previewData: DragItemInfo[] = []
520e41f4b71Sopenharmony_ci  @State colors: Color[] = [Color.Red, Color.Blue, Color.Brown, Color.Gray, Color.Green, Color.Grey, Color.Orange,Color.Pink ,Color.Yellow]
521e41f4b71Sopenharmony_ci  @State numberBadge: number = 0;
522e41f4b71Sopenharmony_ci
523e41f4b71Sopenharmony_ci  @Styles
524e41f4b71Sopenharmony_ci  normalStyles(): void{
525e41f4b71Sopenharmony_ci    .opacity(1.0)
526e41f4b71Sopenharmony_ci  }
527e41f4b71Sopenharmony_ci
528e41f4b71Sopenharmony_ci  @Styles
529e41f4b71Sopenharmony_ci  selectStyles(): void{
530e41f4b71Sopenharmony_ci    .opacity(0.4)
531e41f4b71Sopenharmony_ci  }
532e41f4b71Sopenharmony_ci
533e41f4b71Sopenharmony_ci  onPageShow(): void {
534e41f4b71Sopenharmony_ci    let i: number = 0
535e41f4b71Sopenharmony_ci    for(i=0;i<100;i++){
536e41f4b71Sopenharmony_ci      this.numbers.push(i)
537e41f4b71Sopenharmony_ci      this.isSelectedGrid.push(false)
538e41f4b71Sopenharmony_ci      this.previewData.push({})
539e41f4b71Sopenharmony_ci    }
540e41f4b71Sopenharmony_ci  }
541e41f4b71Sopenharmony_ci
542e41f4b71Sopenharmony_ci  @Builder
543e41f4b71Sopenharmony_ci  RandomBuilder(idx: number) {
544e41f4b71Sopenharmony_ci    Column()
545e41f4b71Sopenharmony_ci      .backgroundColor(this.colors[idx % 9])
546e41f4b71Sopenharmony_ci      .width(50)
547e41f4b71Sopenharmony_ci      .height(50)
548e41f4b71Sopenharmony_ci      .opacity(1.0)
549e41f4b71Sopenharmony_ci  }
550e41f4b71Sopenharmony_ci
551e41f4b71Sopenharmony_ci  build() {
552e41f4b71Sopenharmony_ci    Column({ space: 5 }) {
553e41f4b71Sopenharmony_ci      Grid() {
554e41f4b71Sopenharmony_ci        ForEach(this.numbers, (idx: number) => {
555e41f4b71Sopenharmony_ci          GridItem() {
556e41f4b71Sopenharmony_ci            Column()
557e41f4b71Sopenharmony_ci              .backgroundColor(this.colors[idx % 9])
558e41f4b71Sopenharmony_ci              .width(50)
559e41f4b71Sopenharmony_ci              .height(50)
560e41f4b71Sopenharmony_ci              .opacity(1.0)
561e41f4b71Sopenharmony_ci              .id('grid'+idx)
562e41f4b71Sopenharmony_ci          }
563e41f4b71Sopenharmony_ci          .dragPreview(this.previewData[idx])
564e41f4b71Sopenharmony_ci          .selectable(true)
565e41f4b71Sopenharmony_ci          .selected(this.isSelectedGrid[idx])
566e41f4b71Sopenharmony_ci          // Set the multi-select display effects.
567e41f4b71Sopenharmony_ci          .stateStyles({
568e41f4b71Sopenharmony_ci            normal : this.normalStyles,
569e41f4b71Sopenharmony_ci            selected: this.selectStyles
570e41f4b71Sopenharmony_ci          })
571e41f4b71Sopenharmony_ci          .onClick(()=>{
572e41f4b71Sopenharmony_ci            this.isSelectedGrid[idx] = !this.isSelectedGrid[idx]
573e41f4b71Sopenharmony_ci            if (this.isSelectedGrid[idx]) {
574e41f4b71Sopenharmony_ci              this.numberBadge++;
575e41f4b71Sopenharmony_ci              let gridItemName = 'grid' + idx
576e41f4b71Sopenharmony_ci              // Call the get API in componentSnapshot to obtain the component snapshot pixel map on selection.
577e41f4b71Sopenharmony_ci              componentSnapshot.get(gridItemName, (error: Error, pixmap: image.PixelMap)=>{
578e41f4b71Sopenharmony_ci                this.pixmap = pixmap
579e41f4b71Sopenharmony_ci                this.previewData[idx] = {
580e41f4b71Sopenharmony_ci                  pixelMap:this.pixmap
581e41f4b71Sopenharmony_ci                }
582e41f4b71Sopenharmony_ci              })
583e41f4b71Sopenharmony_ci            } else {
584e41f4b71Sopenharmony_ci              this.numberBadge--;
585e41f4b71Sopenharmony_ci            }
586e41f4b71Sopenharmony_ci          })
587e41f4b71Sopenharmony_ci          // Enable multiselect and set the number badge.
588e41f4b71Sopenharmony_ci          .dragPreviewOptions({numberBadge: this.numberBadge},{isMultiSelectionEnabled:true,defaultAnimationBeforeLifting:true})
589e41f4b71Sopenharmony_ci          .onDragStart(()=>{
590e41f4b71Sopenharmony_ci          })
591e41f4b71Sopenharmony_ci        }, (idx: string) => idx)
592e41f4b71Sopenharmony_ci      }
593e41f4b71Sopenharmony_ci      .columnsTemplate('1fr 1fr 1fr 1fr 1fr')
594e41f4b71Sopenharmony_ci      .columnsGap(5)
595e41f4b71Sopenharmony_ci      .rowsGap(10)
596e41f4b71Sopenharmony_ci      .backgroundColor(0xFAEEE0)
597e41f4b71Sopenharmony_ci    }.width('100%').margin({ top: 5 })
598e41f4b71Sopenharmony_ci  }
599e41f4b71Sopenharmony_ci}
600e41f4b71Sopenharmony_ci```
601