• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Drag and Drop Control
2
3The drag and drop control attributes set whether a component can respond to drag events.
4
5> **NOTE**
6>
7> The APIs of this module are supported since API version 10. Updates will be marked with a superscript to indicate their earliest API version.
8
9The ArkUI framework implements the drag and drop capability 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). To enable drag and drop for these components, you only need to set their **draggable** attribute to **true**.
10
11- The following component supports drag actions by default: **\<Search>**, **\<TextInput>**, **\<TextArea>**, **\<RichEditor>**, **\<Text>**, **\<Image>**, **\<FormComponent>**, **\<Hyperlink>**
12
13- The following component supports drop actions by default: **\<Search>**, **\<TextInput>**, **\<TextArea>**, **\<Video>**
14
15You can also define drag responses by implementing common drag events.
16
17To 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**.
18
19## allowDrop
20
21allowDrop(value: Array&lt;UniformDataType&gt;)
22
23Type of data that can be dropped to the component.
24
25**System capability**: SystemCapability.ArkUI.ArkUI.Full
26
27**Parameters**
28
29| Name| Type                                                        | Mandatory| Description                                           |
30| ------ | ------------------------------------------------------------ | ---- | ----------------------------------------------- |
31| value  | Array\<[UniformDataType](../apis/js-apis-data-uniformTypeDescriptor.md#uniformdatatype)> | Yes  | Type of data that can be dropped to the component.<br>Default value: empty|
32
33## draggable
34
35draggable(value: boolean)
36
37Whether the component is draggable.
38
39**System capability**: SystemCapability.ArkUI.ArkUI.Full
40
41**Parameters**
42
43| Name| Type   | Mandatory| Description                                          |
44| ------ | ------- | ---- | ---------------------------------------------- |
45| value  | boolean | Yes  | Whether the component is draggable.<br>Default value: **false**|
46
47## dragPreview<sup>11+</sup>
48
49dragPreview(value: CustomBuilder | DragItemInfo)
50
51Sets the preview displayed when the component is dragged
52
53**System capability**: SystemCapability.ArkUI.ArkUI.Full
54
55**Parameters**
56
57| Name| Type                                                        | Mandatory| Description                                                        |
58| ------ | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ |
59| value  | [CustomBuilder](ts-types.md#custombuilder8) \| [DragItemInfo](ts-universal-events-drag-drop.md#dragiteminfo) | 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/js-apis-image.md#pixelmap7) in [DragItemInfo](ts-universal-events-drag-drop.md#dragiteminfo) to set the preview.<br>Default value: empty<br>|
60
61## dragPreviewOptions<sup>11+</sup>
62
63dragPreviewOptions(value: DragPreviewOptions)
64
65Sets how the drag preview is processed when the component is dragged. This API works only for **onDragStart**.
66
67**System capability**: SystemCapability.ArkUI.ArkUI.Full
68
69**Parameters**
70
71| Name| Type                                                     | Mandatory| Description                                                        |
72| ------ | --------------------------------------------------------- | ---- | ------------------------------------------------------------ |
73| value  | [DragPreviewOptions](#dragpreviewoptions11)<sup>11+</sup> | Yes  | How the drag preview is processed when the component is dragged.<br>Default value: empty|
74
75## DragPreviewOptions<sup>11+</sup>
76
77| Name| Type| Mandatory| Description|
78| -------- | -------- | -------- | -------- |
79| mode | [DragPreviewMode](#dragpreviewmode11) | No| How the background image is processed when the component is dragged.<br>Default value: **DragPreviewMode.AUTO**<br>|
80
81## DragPreviewMode<sup>11+</sup>
82
83| Name| Value| Description|
84| -------- | ------- | -------- |
85| AUTO  | 0 | The system automatically changes the position of the dragged point based on the scenario and automatically scales the background image based on set rules.|
86| DISABLE_SCALE  | 1 | The system does not scale the background image.|
87
88## Example
89### Example 1
90Example of using the **allowDrop** and **draggable** attributes:
91
92```ts
93// xxx.ets
94import UDC from '@ohos.data.unifiedDataChannel';
95import UTD from '@ohos.data.uniformTypeDescriptor';
96
97@Entry
98@Component
99struct ImageExample {
100  @State uri: string = ""
101  @State AblockArr: string[] = []
102  @State BblockArr: string[] = []
103  @State AVisible: Visibility = Visibility.Visible
104  @State dragSuccess :Boolean = false
105
106  build() {
107    Column() {
108      Text ('Image drag and drop')
109        .fontSize('30dp')
110      Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceAround }) {
111        Image($r('app.media.icon'))
112          .width(100)
113          .height(100)
114          .border({ width: 1 })
115          .visibility(this.AVisible)
116          .draggable(true)
117          .onDragEnd((event: DragEvent) => {
118            let ret = event.getResult();
119            if(ret == 0) {
120              console.log("enter ret == 0")
121              this.AVisible = Visibility.Hidden;
122            } else {
123              console.log("enter ret != 0")
124              this.AVisible = Visibility.Visible;
125            }
126          })
127      }
128      .margin({ bottom: 20 })
129      Row() {
130        Column(){
131          Text('Invalid drop target')
132            .fontSize('15dp')
133            .height('10%')
134          List(){
135            ForEach(this.AblockArr, (item:string, index) => {
136              ListItem() {
137                Image(item)
138                  .width(100)
139                  .height(100)
140                  .border({width: 1})
141              }
142              .margin({ left: 30 , top : 30})
143            }, (item:string) => item)
144          }
145          .height('90%')
146          .width('100%')
147          .allowDrop([UTD.UniformDataType.TEXT])
148          .onDrop((event?: DragEvent, extraParams?: string) => {
149            this.uri = JSON.parse(extraParams as string).extraInfo;
150            this.AblockArr.splice(JSON.parse(extraParams as string).insertIndex, 0, this.uri);
151            console.log("ondrop not udmf data");
152          })
153          .border({width: 1})
154        }
155        .height("50%")
156        .width("45%")
157        .border({ width: 1 })
158        .margin({ left: 12 })
159        Column(){
160          Text ('Valid drop target')
161            .fontSize('15dp')
162            .height('10%')
163          List(){
164            ForEach(this.BblockArr, (item:string, index) => {
165              ListItem() {
166                Image(item)
167                  .width(100)
168                  .height(100)
169                  .border({width: 1})
170              }
171              .margin({ left: 30 , top : 30})
172            }, (item:string) => item)
173          }
174          .border({width: 1})
175          .height('90%')
176          .width('100%')
177          .allowDrop([UTD.UniformDataType.IMAGE])
178          .onDrop((event?: DragEvent, extraParams?: string) => {
179            console.log("enter onDrop")
180            let dragData:UnifiedData = (event as DragEvent).getData() as UnifiedData;
181            if(dragData != undefined) {
182              let arr:Array<UDC.UnifiedRecord> = dragData.getRecords();
183              if(arr.length > 0) {
184                let image = arr[0] as UDC.Image;
185                this.uri = image.imageUri;
186                this.BblockArr.splice(JSON.parse(extraParams as string).insertIndex, 0, this.uri);
187              } else {
188                console.log(`dragData arr is null`)
189              }
190            } else {
191              console.log(`dragData  is undefined`)
192            }
193            console.log("ondrop udmf data");
194            this.dragSuccess = true
195          })
196        }
197        .height("50%")
198        .width("45%")
199        .border({ width: 1 })
200        .margin({ left: 12 })
201      }
202    }.width('100%')
203  }
204}
205```
206
207![dragImage1.jpeg](figures/dragImage1.jpeg)
208
209![dragImage2.jpeg](figures/dragImage2.jpeg)
210
211![dragImage3.jpeg](figures/dragImage3.jpeg)
212
213### Example 2
214Example of using the **dragPreview** attribute:
215```ts
216// xxx.ets
217@Entry
218@Component
219struct DragPreviewDemo{
220  @Builder dragPreviewBuilder() {
221    Column() {
222      Text("dragPreview")
223        .width(150)
224        .height(50)
225        .fontSize(20)
226        .borderRadius(10)
227        .textAlign(TextAlign.Center)
228        .fontColor(Color.Black)
229        .backgroundColor(Color.Pink)
230    }
231  }
232
233  @Builder MenuBuilder() {
234    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
235      Text("menu item 1")
236        .fontSize(15)
237        .width(100)
238        .height(40)
239        .textAlign(TextAlign.Center)
240        .fontColor(Color.Black)
241        .backgroundColor(Color.Pink)
242      Divider()
243        .height(5)
244      Text("menu item 2")
245        .fontSize(15)
246        .width(100)
247        .height(40)
248        .textAlign(TextAlign.Center)
249        .fontColor(Color.Black)
250        .backgroundColor(Color.Pink)
251    }
252    .width(100)
253  }
254
255  build() {
256    Row() {
257      Column() {
258        Image('/resource/image.jpeg')
259          .width("30%")
260          .draggable(true)
261          .bindContextMenu(this.MenuBuilder, ResponseType.LongPress)
262          .onDragStart(() => {
263            console.log("Image onDragStart")
264          })
265          .dragPreview(this.dragPreviewBuilder)
266      }
267      .width("100%")
268    }
269    .height("100%")
270  }
271}
272```
273
274![dragPreview.gif](figures/dragPreview.gif)
275
276### Example 3
277Example of using the **dragPreviewOptions** attribute:
278```ts
279// xxx.ets
280@Entry
281@Component
282struct dragPreviewOptionsDemo{
283  build() {
284    Row() {
285      Column() {
286        Image('/resource/image.jpeg')
287          .margin({ top: 10 })
288          .width("100%")
289          .draggable(true)
290          .dragPreviewOptions({ mode: DragPreviewMode.AUTO })
291      }
292      .width("100%")
293      .height("100%")
294    }
295  }
296}
297```
298
299![dragPreviewOptions.gif](figures/dragPreviewOptions.gif)
300