• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Class (DragController)
2<!--Kit: ArkUI-->
3<!--Subsystem: ArkUI-->
4<!--Owner: @jiangtao92-->
5<!--Designer: @piggyguy-->
6<!--Tester: @songyanhong-->
7<!--Adviser: @HelloCrease-->
8
9Provides APIs for initiating drag actions. When receiving a gesture event, such as a touch or long-press event, an application can initiate a drag action and carry drag information therein.
10
11> **NOTE**
12>
13> - The initial APIs of this module are supported since API version 10. Updates will be marked with a superscript to indicate their earliest API version.
14>
15> - The initial APIs of this class are supported since API version 11.
16>
17> - In the following API examples, you must first use [getDragController()](arkts-apis-uicontext-uicontext.md#getdragcontroller11) in **UIContext** to obtain a **DragController** instance, and then call the APIs using the obtained instance.
18
19## executeDrag<sup>11+</sup>
20
21executeDrag(custom: CustomBuilder | DragItemInfo, dragInfo: dragController.DragInfo, callback: AsyncCallback&lt;dragController.DragEventParam&gt;): void
22
23Initiates a drag action, with the object to be dragged and the drag information passed in. This API uses a callback to return the drag event result.
24
25**Atomic service API**: This API can be used in atomic services since API version 12.
26
27**System capability**: SystemCapability.ArkUI.ArkUI.Full
28
29**Parameters**
30
31| Name  | Type                                                        | Mandatory| Description                                                        |
32| -------- | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ |
33| custom   | [CustomBuilder](arkui-ts/ts-types.md#custombuilder8) \| [DragItemInfo](arkui-ts/ts-universal-events-drag-drop.md#dragiteminfo) | Yes  | Object to be dragged.<br> **NOTE**<br>The global builder is not supported. If the [Image](arkui-ts/ts-basic-components-image.md) component is used in the builder, enable synchronous loading, that is, set the [syncLoad](arkui-ts/ts-basic-components-image.md#syncload8) attribute of the component to **true**. The builder is used only to generate the image displayed during the current dragging. If the root component of the builder has zero width or height, it will cause failure in drag image generation, which in turn breaks the entire drag operation. Changes to the builder, if any, apply to the next dragging, but not to the current dragging.|
34| dragInfo | [dragController.DragInfo](js-apis-arkui-dragController.md#draginfo) | Yes  | Drag information.                                                  |
35| callback | [AsyncCallback](../apis-basic-services-kit/js-apis-base.md#asynccallback)&lt;[dragController.DragEventParam](js-apis-arkui-dragController.md#drageventparam12)&gt; | Yes  | Callback used to return the result.<br>- **event**: drag event information that includes only the drag result.<br>- **extraParams**: extra information about the drag event.|
36
37**Error codes**
38
39For details about the error codes, see [Universal Error Codes](../errorcode-universal.md).
40
41| ID| Error Message     |
42| -------- | ------------- |
43| 401      | Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; 2.Incorrect parameters types; 3. Parameter verification failed. |
44| 100001   | Internal handling failed. |
45
46**Example**
47
48```ts
49import { dragController } from '@kit.ArkUI';
50import { unifiedDataChannel } from '@kit.ArkData';
51
52@Entry
53@Component
54struct DragControllerPage {
55  @Builder DraggingBuilder() {
56    Column() {
57      Text("DraggingBuilder")
58    }
59    .width(100)
60    .height(100)
61    .backgroundColor(Color.Blue)
62  }
63
64  build() {
65    Column() {
66      Button('touch to execute drag')
67        .onTouch((event?: TouchEvent) => {
68          if (event) {
69            if (event.type == TouchType.Down) {
70              let text = new unifiedDataChannel.Text();
71              let unifiedData = new unifiedDataChannel.UnifiedData(text);
72
73              let dragInfo: dragController.DragInfo = {
74                pointerId: 0,
75                data: unifiedData,
76                extraParams: ''
77              };
78              class tmp {
79                event: DragEvent | undefined = undefined;
80                extraParams: string = '';
81              }
82              let eve: tmp = new tmp();
83              this.getUIContext().getDragController().executeDrag(() => { this.DraggingBuilder() }, dragInfo, (err, eve) => {
84                if (eve.event) {
85                  if (eve.event.getResult() == DragResult.DRAG_SUCCESSFUL) {
86                    // ...
87                  } else if (eve.event.getResult() == DragResult.DRAG_FAILED) {
88                    // ...
89                  }
90                }
91              })
92            }
93          }
94        })
95    }
96  }
97}
98```
99
100## executeDrag<sup>11+</sup>
101
102executeDrag(custom: CustomBuilder | DragItemInfo, dragInfo: dragController.DragInfo): Promise&lt;dragController.DragEventParam&gt;
103
104Initiates a drag action, with the object to be dragged and the drag information passed in. This API uses a promise to return the drag event result.
105
106**Atomic service API**: This API can be used in atomic services since API version 12.
107
108**System capability**: SystemCapability.ArkUI.ArkUI.Full
109
110**Parameters**
111
112| Name  | Type                                                        | Mandatory| Description                            |
113| -------- | ------------------------------------------------------------ | ---- | -------------------------------- |
114| custom   | [CustomBuilder](arkui-ts/ts-types.md#custombuilder8) \| [DragItemInfo](arkui-ts/ts-universal-events-drag-drop.md#dragiteminfo) | Yes  | Object to be dragged.|
115| dragInfo | [dragController.DragInfo](js-apis-arkui-dragController.md#draginfo)                                        | Yes  | Drag information.                      |
116
117**Return value**
118
119| Type                                                        | Description                                                        |
120| ------------------------------------------------------------ | ------------------------------------------------------------ |
121| Promise&lt;[dragController.DragEventParam](js-apis-arkui-dragController.md#drageventparam12)&gt; | Promise used to return the result.<br>- **event**: drag event information that includes only the drag result.<br>- **extraParams**: extra information about the drag event.|
122
123**Error codes**
124
125For details about the error codes, see [Universal Error Codes](../errorcode-universal.md).
126
127| ID| Error Message     |
128| -------- | ------------- |
129| 401      | Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; 2.Incorrect parameters types; 3. Parameter verification failed. |
130| 100001   | Internal handling failed. |
131
132**Example**
133
134```ts
135import { dragController } from '@kit.ArkUI';
136import { image } from '@kit.ImageKit';
137import { unifiedDataChannel } from '@kit.ArkData';
138
139@Entry
140@Component
141struct DragControllerPage {
142  @State pixmap: image.PixelMap | null = null;
143
144  @Builder DraggingBuilder() {
145    Column() {
146      Text("DraggingBuilder")
147    }
148    .width(100)
149    .height(100)
150    .backgroundColor(Color.Blue)
151  }
152
153  @Builder PixmapBuilder() {
154    Column() {
155      Text("PixmapBuilder")
156    }
157    .width(100)
158    .height(100)
159    .backgroundColor(Color.Blue)
160  }
161
162  build() {
163    Column() {
164      Button('touch to execute drag')
165        .onTouch((event?: TouchEvent) => {
166          if (event) {
167            if (event.type == TouchType.Down) {
168              let text = new unifiedDataChannel.Text();
169              let unifiedData = new unifiedDataChannel.UnifiedData(text);
170
171              let dragInfo: dragController.DragInfo = {
172                pointerId: 0,
173                data: unifiedData,
174                extraParams: ''
175              };
176              let pb: CustomBuilder = (): void => { this.PixmapBuilder() };
177              this.getUIContext().getComponentSnapshot().createFromBuilder(pb).then((pix: image.PixelMap) => {
178                this.pixmap = pix;
179                let dragItemInfo: DragItemInfo = {
180                  pixelMap: this.pixmap,
181                  builder: () => { this.DraggingBuilder() },
182                  extraInfo: "DragItemInfoTest"
183                };
184
185                class tmp {
186                  event: DragResult | undefined = undefined;
187                  extraParams: string = '';
188                }
189                let eve: tmp = new tmp();
190                this.getUIContext().getDragController().executeDrag(dragItemInfo, dragInfo)
191                  .then((eve) => {
192                    if (eve.event.getResult() == DragResult.DRAG_SUCCESSFUL) {
193                      // ...
194                    } else if (eve.event.getResult() == DragResult.DRAG_FAILED) {
195                      // ...
196                    }
197                  })
198                  .catch((err: Error) => {
199                  })
200              })
201            }
202          }
203        })
204    }
205    .width('100%')
206    .height('100%')
207  }
208}
209```
210
211## createDragAction<sup>11+</sup>
212
213createDragAction(customArray: Array&lt;CustomBuilder \| DragItemInfo&gt;, dragInfo: dragController.DragInfo): dragController.DragAction
214
215Creates a drag action object for initiating drag and drop operations. You need to explicitly specify one or more drag previews, the drag data, and the drag handle point. If a drag operation initiated by an existing drag action object is not completed, no new object can be created, and calling the API will throw an exception. After the lifecycle of the drag action object ends, the callback functions registered on this object become invalid. Therefore, it is necessary to hold this object within a longer scope and replace the old value with a new object returned by **createDragAction** before each drag initiation.
216
217Note: You are advised to control the number of drag previews. If too many previews are passed in, the drag efficiency may be affected.
218
219**Atomic service API**: This API can be used in atomic services since API version 12.
220
221**System capability**: SystemCapability.ArkUI.ArkUI.Full
222
223**Parameters**
224
225| Name  | Type                                                        | Mandatory| Description                            |
226| --------      | ------------------------------------------------------------ | ---- | -------------------------------- |
227| customArray  | Array&lt;[CustomBuilder](arkui-ts/ts-types.md#custombuilder8) \| [DragItemInfo](arkui-ts/ts-universal-events-drag-drop.md#dragiteminfo)&gt; | Yes  | Object to be dragged.|
228| dragInfo | [dragController.DragInfo](js-apis-arkui-dragController.md#draginfo)                                | Yes  | Drag information.                      |
229
230**Return value**
231
232| Type                                                  | Description              |
233| ------------------------------------------------------ | ------------------ |
234| [dragController.DragAction](js-apis-arkui-dragController.md#dragaction11)| **DragAction** object, which is used to subscribe to drag state changes and start the drag service.|
235
236**Error codes**
237
238For details about the error codes, see [Universal Error Codes](../errorcode-universal.md).
239
240| ID| Error Message     |
241| -------- | ------------- |
242| 401      | Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; 2.Incorrect parameters types; 3. Parameter verification failed. |
243| 100001   | Internal handling failed. |
244
245**Example**
246
2471. In the **EntryAbility.ets** file, obtain the UI context and save it to LocalStorage.
248
249```ts
250import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
251import { hilog } from '@kit.PerformanceAnalysisKit';
252import { window, UIContext } from '@kit.ArkUI';
253
254let uiContext: UIContext;
255let localStorage: LocalStorage = new LocalStorage('uiContext');
256
257export default class EntryAbility extends UIAbility {
258  storage: LocalStorage = localStorage;
259  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
260    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
261  }
262
263  onDestroy(): void {
264    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
265  }
266
267  onWindowStageCreate(windowStage: window.WindowStage): void {
268    // Main window is created, set main page for this ability
269    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
270
271    windowStage.loadContent('pages/Index', this.storage, (err, data) => {
272      if (err.code) {
273        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
274        return;
275      }
276      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
277      windowStage.getMainWindow((err, data) =>
278      {
279        if (err.code) {
280          console.error('Failed to abtain the main window. Cause:' + err.message);
281          return;
282        }
283        let windowClass: window.Window = data;
284        uiContext = windowClass.getUIContext();
285        this.storage.setOrCreate<UIContext>('uiContext', uiContext);
286        // Obtain a UIContext instance.
287      });
288    });
289  }
290
291  onWindowStageDestroy(): void {
292    // Main window is destroyed, release UI related resources
293    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
294  }
295
296  onForeground(): void {
297    // Ability has brought to foreground
298    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
299  }
300
301  onBackground(): void {
302    // Ability has back to background
303    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
304  }
305}
306```
3072. Call **this.getUIContext().getSharedLocalStorage()** to obtain the UI context and then use the **DragController** object obtained to perform subsequent operations.
308```ts
309import { dragController, componentSnapshot, UIContext, DragController } from '@kit.ArkUI';
310import { image } from '@kit.ImageKit';
311import { unifiedDataChannel } from '@kit.ArkData';
312
313@Entry()
314@Component
315struct DragControllerPage {
316  @State pixmap: image.PixelMap | null = null;
317  private dragAction: dragController.DragAction | null = null;
318  customBuilders: Array<CustomBuilder | DragItemInfo> = new Array<CustomBuilder | DragItemInfo>();
319  storages = this.getUIContext().getSharedLocalStorage();
320
321  @Builder DraggingBuilder() {
322    Column() {
323      Text("DraggingBuilder")
324    }
325    .width(100)
326    .height(100)
327    .backgroundColor(Color.Blue)
328  }
329
330  build() {
331    Column() {
332
333      Column() {
334        Text("Test")
335      }
336      .width(100)
337      .height(100)
338      .backgroundColor(Color.Red)
339
340      Button('Drag Multiple Objects').onTouch((event?: TouchEvent) => {
341        if (event) {
342          if (event.type == TouchType.Down) {
343            console.info("muti drag Down by listener");
344            this.customBuilders.push(() => { this.DraggingBuilder() });
345            this.customBuilders.push(() => { this.DraggingBuilder() });
346            this.customBuilders.push(() => { this.DraggingBuilder() });
347            let text = new unifiedDataChannel.Text();
348            let unifiedData = new unifiedDataChannel.UnifiedData(text);
349            let dragInfo: dragController.DragInfo = {
350              pointerId: 0,
351              data: unifiedData,
352              extraParams: ''
353            };
354            try{
355              let uiContext: UIContext = this.storages?.get<UIContext>('uiContext') as UIContext;
356              this.dragAction = uiContext.getDragController().createDragAction(this.customBuilders, dragInfo);
357              if (!this.dragAction) {
358                console.info("listener dragAction is null");
359                return;
360              }
361              this.dragAction.on('statusChange', (dragAndDropInfo) => {
362                if (dragAndDropInfo.status == dragController.DragStatus.STARTED) {
363                  console.info("drag has start");
364                } else if (dragAndDropInfo.status == dragController.DragStatus.ENDED) {
365                  console.info("drag has end");
366                  if (!this.dragAction) {
367                    return;
368                  }
369                  this.customBuilders.splice(0, this.customBuilders.length);
370                  this.dragAction.off('statusChange');
371                }
372              })
373              this.dragAction.startDrag().then(() => {}).catch((err: Error) => {
374                console.error("start drag Error:" + err.message);
375              })
376            } catch(err) {
377              console.error("create dragAction Error:" + err.message);
378            }
379          }
380        }
381      }).margin({ top: 20 })
382    }
383  }
384}
385```
386
387## getDragPreview<sup>11+</sup>
388
389getDragPreview(): dragController.DragPreview
390
391Obtains the **DragPreview** object, which represents the preview displayed during a drag operation.
392
393**Atomic service API**: This API can be used in atomic services since API version 12.
394
395**System capability**: SystemCapability.ArkUI.ArkUI.Full
396
397**Return value**
398
399| Type                                                        | Description                                                        |
400| ------------------------------------------------------------ | ------------------------------------------------------------ |
401| [dragController.DragPreview](js-apis-arkui-dragController.md#dragpreview11) | **DragPreview** object. It provides the API for setting the preview style. It does not work in the **OnDrop** and **OnDragEnd** callbacks.|
402
403**Error codes**: For details about universal error codes, see [Universal Error Codes](../errorcode-universal.md).
404
405**Example**
406
407See the example for [animate](js-apis-arkui-dragController.md#animate11).
408
409## setDragEventStrictReportingEnabled<sup>12+</sup>
410
411setDragEventStrictReportingEnabled(enable: boolean): void
412
413Sets whether the **onDragLeave** callback of the parent component is triggered when an item is dragged from the parent to the child component.
414
415**Atomic service API**: This API can be used in atomic services since API version 12.
416
417**System capability**: SystemCapability.ArkUI.ArkUI.Full
418
419**Parameters**
420
421| Name| Type   | Mandatory| Description                                                        |
422| ------ | ------- | ---- | ------------------------------------------------------------ |
423| enable | boolean | Yes  | Whether the **onDragLeave** callback of the parent component is triggered when an item is dragged from the parent to the child component. The value **true** means the **onDragLeave** callback of the parent component is triggered, and **false** means the opposite.|
424
425**Example**
426
427```ts
428import { UIAbility } from '@kit.AbilityKit';
429import { window, UIContext } from '@kit.ArkUI';
430
431 export default class EntryAbility extends UIAbility {
432   onWindowStageCreate(windowStage: window.WindowStage): void {
433       windowStage.loadContent('pages/Index', (err, data) => {
434         if (err.code) {
435         return;
436       }
437       windowStage.getMainWindow((err, data) => {
438         if (err.code) {
439           return;
440         }
441         let windowClass: window.Window = data;
442         let uiContext: UIContext = windowClass.getUIContext();
443         uiContext.getDragController().setDragEventStrictReportingEnabled(true);
444     });
445   });
446 }
447}
448```
449
450## cancelDataLoading<sup>15+</sup>
451
452cancelDataLoading(key: string): void
453
454Cancels the data loading initiated by the [startDataLoading](arkui-ts/ts-universal-events-drag-drop.md#dragevent7) API.
455
456**Atomic service API**: This API can be used in atomic services since API version 15.
457
458**System capability**: SystemCapability.ArkUI.ArkUI.Full
459
460**Parameters**
461
462| Name| Type   | Mandatory| Description                                                        |
463| ------ | ------- | ---- | ------------------------------------------------------------ |
464| key | string | Yes  | Identifier for the drag data. It is used to distinguish between different drag operations. The key can be obtained through the **startDataLoading** API.|
465
466**Error codes**
467
468For details about the error codes, see [Universal Error Codes](../errorcode-universal.md) and [Drag Event Error Codes](./errorcode-drag-event.md).
469
470| ID| Error Message                                                    |
471| -------- | ------------------------------------------------------------ |
472| 401      | Parameter error. |
473| 190004      | Operation failed. |
474
475## notifyDragStartRequest<sup>18+</sup>
476
477notifyDragStartRequest(requestStatus: dragController.DragStartRequestStatus): void
478
479Controls whether the application can initiate a drag operation.
480
481**Atomic service API**: This API can be used in atomic services since API version 18.
482
483**System capability**: SystemCapability.ArkUI.ArkUI.Full
484
485**Parameters**
486
487| Name| Type  | Mandatory| Description                                                       |
488| ------ | ------- | ---- | ------------------------------------------------------------ |
489| requestStatus  | [dragController.DragStartRequestStatus](js-apis-arkui-dragController.md#dragstartrequeststatus18)    | Yes |Whether the application can initiate a drag operation.|
490
491**Example**
492
493```ts
494import { unifiedDataChannel } from '@kit.ArkData';
495import { image } from '@kit.ImageKit';
496import { dragController } from '@kit.ArkUI';
497
498// xxx.ets
499@Entry
500@Component
501struct NormalEts {
502  @State finished: boolean = false;
503  @State timeout1: number = 1;
504  @State pixmap: image.PixelMap | undefined = undefined;
505  @State unifiedData1: unifiedDataChannel.UnifiedData | undefined = undefined;
506  @State previewData: DragItemInfo | undefined = undefined;
507
508  loadData() {
509    let timeout = setTimeout(() => {
510      this.getUIContext().getComponentSnapshot().get("image1", (error: Error, pixmap: image.PixelMap) => {
511        this.pixmap = pixmap;
512        this.previewData = {
513          pixelMap: this.pixmap
514        };
515      });
516
517      let data: unifiedDataChannel.Image = new unifiedDataChannel.Image();
518      data.imageUri = "app.media.startIcon";
519      let unifiedData = new unifiedDataChannel.UnifiedData(data);
520      this.unifiedData1 = unifiedData;
521
522      this.getUIContext().getDragController().notifyDragStartRequest(dragController.DragStartRequestStatus.READY);
523    }, 4000);
524    this.timeout1 = timeout;
525  }
526
527
528    build() {
529      Column({space: 20}) {
530        Image($r("app.media.startIcon"))
531          .width(300)
532          .height(200)
533          .id("image1")
534          .draggable(true)
535          .dragPreview(this.previewData)
536          .onPreDrag((status: PreDragStatus) => {
537            if (status == PreDragStatus.PREPARING_FOR_DRAG_DETECTION) {
538              this.loadData();
539            } else {
540              clearTimeout(this.timeout1);
541            }
542          })
543          .onDragStart((event: DragEvent) => {
544            if (this.finished == false) {
545              this.getUIContext().getDragController().notifyDragStartRequest(dragController.DragStartRequestStatus.WAITING);
546            } else {
547              event.setData(this.unifiedData1);
548            }
549          })
550          .onDragEnd(() => {
551            this.finished = false;
552          })
553      }
554      .height(400)
555      .backgroundColor(Color.Pink)
556    }
557}
558```
559## enableDropDisallowedBadge<sup>20+</sup>
560
561enableDropDisallowedBadge(enabled: boolean): void
562
563Specifies whether to enable the display of a disallowed badge when dragged content is incompatible with a component's configured [allowDrop](../apis-arkui/arkui-ts/ts-universal-attributes-drag-drop.md#allowdrop) types. With the display enabled, the system automatically shows a disallowed badge during drag operations when the dragged data types have no intersection with the target component's allowed drop types. This API currently does not support [UIExtension](../apis-arkui/js-apis-arkui-uiExtension.md).
564
565**Atomic service API**: This API can be used in atomic services since API version 20.
566
567**System capability**: SystemCapability.ArkUI.ArkUI.Full
568
569**Parameters**
570
571| Name| Type   | Mandatory| Description                                                        |
572| ------ | ------- | ---- | ------------------------------------------------------------ |
573| enabled | boolean | Yes  | Whether to enable the display of a disallowed badge when dragged content is incompatible with a component's configured [allowDrop](../apis-arkui/arkui-ts/ts-universal-attributes-drag-drop.md#allowdrop) types. The value **true** means to enable the display of a disallowed badge, and **false** means the opposite. The default value is **false**.|
574
575**Example**
576
577This example demonstrates how to use the **enableDropDisallowedBadge** API to enable the display of a disallowed badge when dragged content is incompatible with the target component's allowed drop types.
578
579```ts
580import { UIAbility } from '@kit.AbilityKit';
581import { window, UIContext } from '@kit.ArkUI';
582
583 export default class EntryAbility extends UIAbility {
584   onWindowStageCreate(windowStage: window.WindowStage): void {
585       windowStage.loadContent('pages/Index', (err, data) => {
586         if (err.code) {
587         return;
588       }
589       windowStage.getMainWindow((err, data) => {
590         if (err.code) {
591           return;
592         }
593         let windowClass: window.Window = data;
594         let uiContext: UIContext = windowClass.getUIContext();
595         uiContext.getDragController().enableDropDisallowedBadge(true);
596     });
597   });
598 }
599}
600```
601![UIContext](figures/UIContext.png)
602