# Class (DragController)
提供发起主动拖拽的能力,当应用接收到触摸或长按等事件时可以主动发起拖拽的动作,并在其中携带拖拽信息。
> **说明:**
>
> - 本模块首批接口从API version 10开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
>
> - 本Class首批接口从API version 11开始支持。
>
> - 以下API需先使用UIContext中的[getDragController()](arkts-apis-uicontext-uicontext.md#getdragcontroller11)方法获取DragController实例,再通过此实例调用对应方法。
## executeDrag11+
executeDrag(custom: CustomBuilder | DragItemInfo, dragInfo: dragController.DragInfo, callback: AsyncCallback<dragController.DragEventParam>): void
主动发起拖拽能力,传入拖拽发起后跟手效果所拖拽的对象以及携带拖拽信息。通过回调返回拖拽事件结果。
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| -------- | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ |
| custom | [CustomBuilder](arkui-ts/ts-types.md#custombuilder8) \| [DragItemInfo](arkui-ts/ts-universal-events-drag-drop.md#dragiteminfo) | 是 | 拖拽发起后跟手效果所拖拽的对象。
**说明:**
不支持全局builder。如果builder中使用了[Image](arkui-ts/ts-basic-components-image.md)组件,应尽量开启同步加载,即配置Image的[syncLoad](arkui-ts/ts-basic-components-image.md#syncload8)为true。该builder只用于生成当次拖拽中显示的图片。builder的根组件宽高为0时,无法生成拖拽显示的图片导致拖拽失败。builder的修改不会同步到当前正在拖拽的图片,对builder的修改需要在下一次拖拽时生效。 |
| dragInfo | [dragController.DragInfo](js-apis-arkui-dragController.md#draginfo) | 是 | 拖拽信息。 |
| callback | [AsyncCallback](../apis-basic-services-kit/js-apis-base.md#asynccallback)<[dragController.DragEventParam](js-apis-arkui-dragController.md#drageventparam12)> | 是 | 拖拽结束返回结果的回调
- event:拖拽事件信息,仅包括拖拽结果。
- extraParams:拖拽事件额外信息。 |
**错误码:**
以下错误码的详细介绍请参见[通用错误码](../errorcode-universal.md)。
| 错误码ID | 错误信息 |
| -------- | ------------- |
| 401 | Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; 2.Incorrect parameters types; 3. Parameter verification failed. |
| 100001 | Internal handling failed. |
**示例:**
```ts
import { dragController } from '@kit.ArkUI';
import { unifiedDataChannel } from '@kit.ArkData';
class Tmp {
event: DragEvent | undefined = undefined;
extraParams: string = '';
}
@Entry
@Component
struct DragControllerPage {
@Builder DraggingBuilder() {
Column() {
Text("DraggingBuilder")
}
.width(100)
.height(100)
.backgroundColor(Color.Blue)
}
build() {
Column() {
Button('touch to execute drag')
.onTouch((event?: TouchEvent) => {
if (event) {
if (event.type == TouchType.Down) {
let text = new unifiedDataChannel.Text();
let unifiedData = new unifiedDataChannel.UnifiedData(text);
let dragInfo: dragController.DragInfo = {
pointerId: 0,
data: unifiedData,
extraParams: ''
};
let eve: tmp = new tmp();
this.getUIContext().getDragController().executeDrag(() => { this.DraggingBuilder() }, dragInfo, (err, eve) => {
if (eve.event) {
if (eve.event.getResult() == DragResult.DRAG_SUCCESSFUL) {
// ...
} else if (eve.event.getResult() == DragResult.DRAG_FAILED) {
// ...
}
}
})
}
}
})
}
}
}
```
## executeDrag11+
executeDrag(custom: CustomBuilder | DragItemInfo, dragInfo: dragController.DragInfo): Promise<dragController.DragEventParam>
主动发起拖拽能力,传入拖拽发起后跟手效果所拖拽的对象以及携带拖拽信息。通过Promise返回拖拽事件结果。
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| -------- | ------------------------------------------------------------ | ---- | -------------------------------- |
| custom | [CustomBuilder](arkui-ts/ts-types.md#custombuilder8) \| [DragItemInfo](arkui-ts/ts-universal-events-drag-drop.md#dragiteminfo) | 是 | 拖拽发起后跟手效果所拖拽的对象。 |
| dragInfo | [dragController.DragInfo](js-apis-arkui-dragController.md#draginfo) | 是 | 拖拽信息。 |
**返回值:**
| 类型 | 说明 |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| Promise<[dragController.DragEventParam](js-apis-arkui-dragController.md#drageventparam12)> | 拖拽结束返回结果的回调
- event:拖拽事件信息,仅包括拖拽结果。
- extraParams:拖拽事件额外信息。 |
**错误码:**
以下错误码的详细介绍请参见[通用错误码](../errorcode-universal.md)。
| 错误码ID | 错误信息 |
| -------- | ------------- |
| 401 | Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; 2.Incorrect parameters types; 3. Parameter verification failed. |
| 100001 | Internal handling failed. |
**示例:**
```ts
import { dragController } from '@kit.ArkUI';
import { image } from '@kit.ImageKit';
import { unifiedDataChannel } from '@kit.ArkData';
class Tmp {
event: DragResult | undefined = undefined;
extraParams: string = '';
}
@Entry
@Component
struct DragControllerPage {
@State pixmap: image.PixelMap | null = null;
@Builder DraggingBuilder() {
Column() {
Text("DraggingBuilder")
}
.width(100)
.height(100)
.backgroundColor(Color.Blue)
}
@Builder PixmapBuilder() {
Column() {
Text("PixmapBuilder")
}
.width(100)
.height(100)
.backgroundColor(Color.Blue)
}
build() {
Column() {
Button('touch to execute drag')
.onTouch((event?: TouchEvent) => {
if (event) {
if (event.type == TouchType.Down) {
let text = new unifiedDataChannel.Text();
let unifiedData = new unifiedDataChannel.UnifiedData(text);
let dragInfo: dragController.DragInfo = {
pointerId: 0,
data: unifiedData,
extraParams: ''
};
let pb: CustomBuilder = (): void => { this.PixmapBuilder() };
this.getUIContext().getComponentSnapshot().createFromBuilder(pb).then((pix: image.PixelMap) => {
this.pixmap = pix;
let dragItemInfo: DragItemInfo = {
pixelMap: this.pixmap,
builder: () => { this.DraggingBuilder() },
extraInfo: "DragItemInfoTest"
};
let eve: tmp = new tmp();
this.getUIContext().getDragController().executeDrag(dragItemInfo, dragInfo)
.then((eve) => {
if (eve.event.getResult() == DragResult.DRAG_SUCCESSFUL) {
// ...
} else if (eve.event.getResult() == DragResult.DRAG_FAILED) {
// ...
}
})
.catch((err: Error) => {
})
})
}
}
})
}
.width('100%')
.height('100%')
}
}
```
## createDragAction11+
createDragAction(customArray: Array<CustomBuilder \| DragItemInfo>, dragInfo: dragController.DragInfo): dragController.DragAction
创建拖拽的Action对象,需要显式指定拖拽背板图(可多个),以及拖拽的数据,跟手点等信息;当通过一个已创建的Action对象发起的拖拽未结束时,无法再次创建新的Action对象,接口会抛出异常;当Action对象的生命周期结束后,注册在该对象上的回调函数会失效,因此需要在一个尽量长的作用域下持有该对象,并在每次发起拖拽前通过createDragAction返回新的对象覆盖旧值。
**说明:** 建议控制传递的拖拽背板数量,传递过多容易导致拖起的效率问题。
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| -------- | ------------------------------------------------------------ | ---- | -------------------------------- |
| customArray | Array<[CustomBuilder](arkui-ts/ts-types.md#custombuilder8) \| [DragItemInfo](arkui-ts/ts-universal-events-drag-drop.md#dragiteminfo)> | 是 | 拖拽发起后跟手效果所拖拽的对象。 |
| dragInfo | [dragController.DragInfo](js-apis-arkui-dragController.md#draginfo) | 是 | 拖拽信息。 |
**返回值:**
| 类型 | 说明 |
| ------------------------------------------------------ | ------------------ |
| [dragController.DragAction](js-apis-arkui-dragController.md#dragaction11)| 创建拖拽Action对象,主要用于后面实现注册监听拖拽状态改变事件和启动拖拽服务。 |
**错误码:**
以下错误码的详细介绍请参见[通用错误码](../errorcode-universal.md)。
| 错误码ID | 错误信息 |
| -------- | ------------- |
| 401 | Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; 2.Incorrect parameters types; 3. Parameter verification failed. |
| 100001 | Internal handling failed. |
**示例:**
1.在EntryAbility.ets中获取UI上下文并保存至LocalStorage中。
```ts
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window, UIContext } from '@kit.ArkUI';
let uiContext: UIContext;
let localStorage: LocalStorage = new LocalStorage('uiContext');
export default class EntryAbility extends UIAbility {
storage: LocalStorage = localStorage;
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy(): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/Index', this.storage, (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
windowStage.getMainWindow((err, data) =>
{
if (err.code) {
console.error('Failed to abtain the main window. Cause:' + err.message);
return;
}
let windowClass: window.Window = data;
uiContext = windowClass.getUIContext();
this.storage.setOrCreate('uiContext', uiContext);
// 获取UIContext实例
});
});
}
onWindowStageDestroy(): void {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground(): void {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground(): void {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}
```
2.通过this.getUIContext().getSharedLocalStorage()获取上下文,进而获取DragController对象实施后续操作。
```ts
import { dragController, componentSnapshot, UIContext, DragController } from '@kit.ArkUI';
import { image } from '@kit.ImageKit';
import { unifiedDataChannel } from '@kit.ArkData';
@Entry()
@Component
struct DragControllerPage {
@State pixmap: image.PixelMap | null = null;
private dragAction: dragController.DragAction | null = null;
customBuilders: Array = new Array();
storages = this.getUIContext().getSharedLocalStorage();
@Builder DraggingBuilder() {
Column() {
Text("DraggingBuilder")
}
.width(100)
.height(100)
.backgroundColor(Color.Blue)
}
build() {
Column() {
Column() {
Text("测试")
}
.width(100)
.height(100)
.backgroundColor(Color.Red)
Button('多对象dragAction customBuilder拖拽').onTouch((event?: TouchEvent) => {
if (event) {
if (event.type == TouchType.Down) {
console.info("muti drag Down by listener");
this.customBuilders.push(() => { this.DraggingBuilder() });
this.customBuilders.push(() => { this.DraggingBuilder() });
this.customBuilders.push(() => { this.DraggingBuilder() });
let text = new unifiedDataChannel.Text();
let unifiedData = new unifiedDataChannel.UnifiedData(text);
let dragInfo: dragController.DragInfo = {
pointerId: 0,
data: unifiedData,
extraParams: ''
};
try{
let uiContext: UIContext = this.storages?.get('uiContext') as UIContext;
this.dragAction = uiContext.getDragController().createDragAction(this.customBuilders, dragInfo);
if (!this.dragAction) {
console.info("listener dragAction is null");
return;
}
this.dragAction.on('statusChange', (dragAndDropInfo) => {
if (dragAndDropInfo.status == dragController.DragStatus.STARTED) {
console.info("drag has start");
} else if (dragAndDropInfo.status == dragController.DragStatus.ENDED) {
console.info("drag has end");
if (!this.dragAction) {
return;
}
this.customBuilders.splice(0, this.customBuilders.length);
this.dragAction.off('statusChange');
}
})
this.dragAction.startDrag().then(() => {}).catch((err: Error) => {
console.error("start drag Error:" + err.message);
})
} catch(err) {
console.error("create dragAction Error:" + err.message);
}
}
}
}).margin({ top: 20 })
}
}
}
```
## getDragPreview11+
getDragPreview(): dragController.DragPreview
返回一个代表拖拽背板的对象。
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**返回值:**
| 类型 | 说明 |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| [dragController.DragPreview](js-apis-arkui-dragController.md#dragpreview11) | 一个代表拖拽背板的对象,提供背板样式设置的接口,在OnDrop和OnDragEnd回调中使用不生效。 |
**错误码:** 通用错误码请参考[通用错误码说明文档](../errorcode-universal.md)。
**示例:**
请参考[animate](js-apis-arkui-dragController.md#animate11)示例。
## setDragEventStrictReportingEnabled12+
setDragEventStrictReportingEnabled(enable: boolean): void
当目标从父组件拖拽到子组件时,通过该方法设置是否会触发父组件的onDragLeave的回调。
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| ------ | ------- | ---- | ------------------------------------------------------------ |
| enable | boolean | 是 | 将目标从父组件拖拽到子组件时,是否会触发父组件的onDragLeave的回调。true表示触发父组件的onDragLeave的回调,false表示不触发。 |
**示例:**
```ts
import { UIAbility } from '@kit.AbilityKit';
import { window, UIContext } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
return;
}
windowStage.getMainWindow((err, data) => {
if (err.code) {
return;
}
let windowClass: window.Window = data;
let uiContext: UIContext = windowClass.getUIContext();
uiContext.getDragController().setDragEventStrictReportingEnabled(true);
});
});
}
}
```
## cancelDataLoading15+
cancelDataLoading(key: string): void
当使用[startDataLoading](arkui-ts/ts-universal-events-drag-drop.md#dragevent7)获取拖拽数据时,可调用该接口取消数据传输。
**原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| ------ | ------- | ---- | ------------------------------------------------------------ |
| key | string | 是 | 拖拽数据的标识,用于区分每次拖拽。key可通过startDataLoading接口获取。 |
**错误码:**
以下错误码的详细介绍请参见[通用错误码](../errorcode-universal.md)和[拖拽事件错误码](./errorcode-drag-event.md)。
| 错误码ID | 错误信息 |
| -------- | ------------------------------------------------------------ |
| 401 | Parameter error. |
| 190004 | Operation failed. |
## notifyDragStartRequest18+
notifyDragStartRequest(requestStatus: dragController.DragStartRequestStatus): void
控制应用是否可以发起拖拽。
**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填| 说明 |
| ------ | ------- | ---- | ------------------------------------------------------------ |
| requestStatus | [dragController.DragStartRequestStatus](js-apis-arkui-dragController.md#dragstartrequeststatus18) | 是 |定义应用是否可以发起拖拽。|
**示例:**
```ts
// xxx.ets
import { unifiedDataChannel } from '@kit.ArkData';
import { image } from '@kit.ImageKit';
import { dragController } from '@kit.ArkUI';
@Entry
@Component
struct NormalEts {
@State finished: boolean = false;
@State timeout1: number = 1;
@State pixmap: image.PixelMap | undefined = undefined;
@State unifiedData1: unifiedDataChannel.UnifiedData | undefined = undefined;
@State previewData: DragItemInfo | undefined = undefined;
loadData() {
let timeout = setTimeout(() => {
this.getUIContext().getComponentSnapshot().get("image1", (error: Error, pixmap: image.PixelMap) => {
this.pixmap = pixmap;
this.previewData = {
pixelMap: this.pixmap
};
});
let data: unifiedDataChannel.Image = new unifiedDataChannel.Image();
data.imageUri = "app.media.startIcon";
let unifiedData = new unifiedDataChannel.UnifiedData(data);
this.unifiedData1 = unifiedData;
this.getUIContext().getDragController().notifyDragStartRequest(dragController.DragStartRequestStatus.READY);
}, 4000);
this.timeout1 = timeout;
}
build() {
Column({space: 20}) {
Image($r("app.media.startIcon"))
.width(300)
.height(200)
.id("image1")
.draggable(true)
.dragPreview(this.previewData)
.onPreDrag((status: PreDragStatus) => {
if (status == PreDragStatus.PREPARING_FOR_DRAG_DETECTION) {
this.loadData();
} else {
clearTimeout(this.timeout1);
}
})
.onDragStart((event: DragEvent) => {
if (this.finished == false) {
this.getUIContext().getDragController().notifyDragStartRequest(dragController.DragStartRequestStatus.WAITING);
} else {
event.setData(this.unifiedData1);
}
})
.onDragEnd(() => {
this.finished = false;
})
}
.height(400)
.backgroundColor(Color.Pink)
}
}
```
## enableDropDisallowedBadge20+
enableDropDisallowedBadge(enabled: boolean): void
当组件的类型与配置的[allowDrop](../apis-arkui/arkui-ts/ts-universal-attributes-drag-drop.md#allowdrop)无交集时可显示禁用角标。当目标进行拖拽时,通过该方法检查是否显示拖拽禁止角标。该接口暂不支持[UIExtension](../apis-arkui/js-apis-arkui-uiExtension.md)。
**原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| ------ | ------- | ---- | ------------------------------------------------------------ |
| enabled | boolean | 是 | 当组件的类型与配置的[allowDrop](../apis-arkui/arkui-ts/ts-universal-attributes-drag-drop.md#allowdrop)无交集时可显示禁用角标,当目标进行拖拽时,通过enableDropDisallowedBadge方法检查是否显示拖拽禁止角标。true表示显示拖拽禁止角标,false表示不显示拖拽禁止角标。默认值为false。 |
**示例:**
该示例通过enableDropDisallowedBadge接口实现了对目标进行拖拽时显示拖拽禁止角标的功能。
```ts
import { UIAbility } from '@kit.AbilityKit';
import { window, UIContext } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
return;
}
windowStage.getMainWindow((err, data) => {
if (err.code) {
return;
}
let windowClass: window.Window = data;
let uiContext: UIContext = windowClass.getUIContext();
uiContext.getDragController().enableDropDisallowedBadge(true);
});
});
}
}
```
