# 拖拽事件
拖拽事件指组件被长按后拖拽时触发的事件。
> **说明:**
>
> 从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
>
> 应用本身预置的资源文件(即应用在安装前的HAP包中已经存在的资源文件)仅支持本地应用内拖拽。
ArkUI框架对以下组件实现了默认的拖拽能力,支持对数据的拖出或拖入响应。开发者也可以通过实现通用拖拽事件来自定义拖拽响应。
- 默认支持拖出能力的组件(可从组件上拖出数据):[Search](ts-basic-components-search.md)、[TextInput](ts-basic-components-textinput.md)、[TextArea](ts-basic-components-textarea.md)、[RichEditor](ts-basic-components-richeditor.md)、[Text](ts-basic-components-text.md)、[Image](ts-basic-components-image.md)、[FormComponent](ts-basic-components-formcomponent-sys.md)、[Hyperlink](ts-container-hyperlink.md),开发者可通过设置这些组件的[draggable](ts-universal-attributes-drag-drop.md#draggable)属性来控制对默认拖拽能力的使用。
- 默认支持拖入能力的组件(目标组件可响应拖入数据):[Search](ts-basic-components-search.md)、[TextInput](ts-basic-components-textinput.md)、[TextArea](ts-basic-components-textarea.md)、[RichEditor](ts-basic-components-richeditor.md),开发者可通过设置这些组件的[allowDrop](ts-universal-attributes-drag-drop.md#allowdrop)属性为null来禁用对默认拖入能力的支持。
其他组件需要开发者将draggable属性设置为true,并在onDragStart等接口中实现数据传输相关内容,才能正确处理拖拽。
> **说明:**
>
> Text组件需配合[copyOption](ts-basic-components-text.md#copyoption9)一起使用,设置copyOptions为CopyOptions.InApp或者CopyOptions.LocalDevice。
## onDragStart
onDragStart(event: (event: DragEvent, extraParams?: string) => CustomBuilder | DragItemInfo)
第一次拖拽此事件绑定的组件时,长按时间 >= 500ms,然后手指移动距离 >= 10vp,触发回调。
针对默认支持拖出能力的组件,如果开发者设置了onDragStart,优先执行开发者的onDragStart,并根据执行情况决定是否使用系统默认的拖出能力,具体为:
- 如果开发者返回了自定义背板图,则不再使用系统默认的拖拽背板图;
- 如果开发者设置了拖拽数据,则不再使用系统默认填充的拖拽数据。
文本类组件[Text](ts-basic-components-text.md)、[Search](ts-basic-components-search.md)、[TextInput](ts-basic-components-textinput.md)、[TextArea](ts-basic-components-textarea.md)、[RichEditor](ts-basic-components-richeditor.md)对选中的文本内容进行拖拽时,不支持背板图的自定义。当onDragStart与菜单预览一起使用或使用了默认支持拖出能力的组件时,预览及菜单项上的自定义内容不支持拖拽。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
**事件优先级:** 长按触发时间 < 500ms,长按事件优先拖拽事件响应,长按触发时间 >= 500ms,拖拽事件优先长按事件响应。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| ----------- | ------------------------------- | ---- | ------------------ |
| event | (event: [DragEvent](#dragevent), extraParams?: string) => [CustomBuilder](ts-types.md#custombuilder8) \| [DragItemInfo](#dragiteminfo说明) | 是 | 回调函数。
**说明:**
event为拖拽事件信息。
extraParams为拖拽事件额外信息。需要解析为Json格式,参考[extraParams](#extraparams说明)说明。|
**返回值:**
| 类型 | 说明 |
| ------------------------------------------------------------ | ------------------------ |
| [CustomBuilder](ts-types.md#custombuilder8) \| [DragItemInfo](#dragiteminfo说明) | 拽过程中显示的组件信息。
**说明:** 不支持全局builder。 |
## onDragEnter
onDragEnter(event: (event: DragEvent, extraParams?: string) => void)
拖拽进入组件范围内时,触发回调,当监听了[onDrop](#ondrop)事件时,此事件才有效。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| ----------- | ------------------------------- | ---- | ------------------------------ |
| event | (event: [DragEvent](#dragevent), extraParams?: string) => void | 是 | 回调函数。
**说明:**
event为拖拽事件信息,包括拖拽点坐标。
extraParams为拖拽事件额外信息,需要解析为Json格式,参考[extraParams](#extraparams说明)说明。|
## onDragMove
onDragMove(event: (event: DragEvent, extraParams?: string) => void)
拖拽在组件范围内移动时,触发回调,当监听了[onDrop](#ondrop)事件时,此事件才有效。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| ----------- | ------------------------------- | ---- | ------------------------------ |
| event | (event: [DragEvent](#dragevent), extraParams?: string) => void | 是 | 回调函数。
**说明:**
event为拖拽事件信息,包括拖拽点坐标。
extraParams为拖拽事件额外信息,需要解析为Json格式,参考[extraParams](#extraparams说明)说明。|
## onDragLeave
onDragLeave(event: (event: DragEvent, extraParams?: string) => void)
拖拽离开组件范围内时,触发回调,当监听了[onDrop](#ondrop)事件时,此事件才有效。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| ----------- | ------------------------------- | ---- | ------------------------------ |
| event | (event: [DragEvent](#dragevent), extraParams?: string) => void | 是 | 回调函数。
**说明:**
event为拖拽事件信息,包括拖拽点坐标。
extraParams为拖拽事件额外信息,需要解析为Json格式,参考[extraParams](#extraparams说明)说明。|
## onDrop
onDrop(event: (event: DragEvent, extraParams?: string) => void)
绑定此事件的组件可作为拖拽释放目标,当在本组件范围内停止拖拽行为时,触发回调。如果开发者没有在onDrop中主动调用event.setResult()设置拖拽接收的结果,若拖拽组件为系统支持默认拖入的组件,以系统实际处理数据结果为准,其它组件则系统按照数据接收成功处理。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| ----------- | ------------------------------- | ---- | ------------------------------ |
| event | (event: [DragEvent](#dragevent), extraParams?: string) => void | 是 | 回调函数。
**说明:**
event为拖拽事件信息,包括拖拽点坐标。
extraParams为拖拽事件额外信息,需要解析为Json格式,参考[extraParams](#extraparams说明)说明。|
## onDragEnd
onDragEnd(event: (event: DragEvent, extraParams?: string) => void)
绑定此事件的组件触发的拖拽结束后,触发回调。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| ----------- | ------------------------------- | ---- | ------------------------------ |
| event | (event: [DragEvent](#dragevent), extraParams?: string) => void | 是 | 回调函数。
**说明:**
event为拖拽事件信息,不包括拖拽点坐标。
extraParams为拖拽事件额外信息,需要解析为Json格式,参考[extraParams](#extraparams说明)说明。|
## onPreDrag12+
onPreDrag(event: (preDragStatus: PreDragStatus) => void)
绑定此事件的组件,当触发拖拽发起前的不同阶段时,触发回调。
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| ----------- | ------------------------------- | ---- | ------------------------------ |
| callback | Callback<(preDragStatus: [PreDragStatus](#predragstatus12枚举说明)> ) => void | 是 | 回调函数。|
## DragItemInfo说明
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
| 名称 | 类型 | 必填 | 描述 |
| --------- | ---------------------------------------- | ---- | --------------------------------- |
| pixelMap | [PixelMap](../../apis-image-kit/js-apis-image.md#pixelmap7) | 否 | 设置拖拽过程中显示的图片。 |
| builder | [CustomBuilder](ts-types.md#custombuilder8) | 否 | 拖拽过程中显示自定义组件,如果设置了pixelMap,则忽略此值。
**说明:**
不支持全局builder。如果builder中使用了[Image](ts-basic-components-image.md)组件,应尽量开启同步加载,即配置Image的[syncLoad](ts-basic-components-image.md#syncload8)为true。该builder只用于生成当次拖拽中显示的图片,builder的修改不会同步到当前正在拖拽的图片,对builder的修改需要在下一次拖拽时生效。|
| extraInfo | string | 否 | 拖拽项的描述。 |
## extraParams说明
用于返回组件在拖拽中需要用到的额外信息。
extraParams是Json对象转换的string字符串,可以通过Json.parse转换的Json对象获取如下属性。
| 名称 | 类型 | 描述 |
| ------------- | ------ | ---------------------------------------- |
| selectedIndex | number | 当拖拽事件设在父容器的子元素时,selectedIndex表示当前被拖拽子元素是父容器第selectedIndex个子元素,selectedIndex从0开始。
仅在ListItem组件的拖拽事件中生效。 |
| insertIndex | number | 当前拖拽元素在List组件中放下时,insertIndex表示被拖拽元素插入该组件的第insertIndex个位置,insertIndex从0开始。
仅在List组件的拖拽事件中生效。 |
## DragEvent
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
### 属性
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
| 名称 | 类型 | 描述 |
| ------ | ------ | ---------------- |
| useCustomDropAnimation10+ | boolean | 当拖拽结束时,是否使能并使用系统默认落位动效。
应用可将该值设定为true来禁用系统默认落位动效,并实现自己的自定义落位动效。
当不配置或设置为false时,系统默认落位动效生效,当松手位置的控件可接收拖拽的数据时,落位为缩小消失动效,若不可接收数据,则为放大消失动效。
当未禁用系统默认落位动效情况下,应用不应再实现自定义动效,以避免动效上的冲突。|
|dragBehavior10+ | [DragBehavior](#dragbehavior10) | 切换复制和剪贴模式的角标显示状态。 |
### 方法
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
| 名称 | 返回值类型 | 描述 |
| ----------- | ------------------------------- | ------------------------------ |
| setData(unifiedData: [UnifiedData](../../apis-arkdata/js-apis-data-unifiedDataChannel.md#unifieddata))10+ | void | 向DragEvent中设置拖拽相关数据。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
| getData()10+ | [UnifiedData](../../apis-arkdata/js-apis-data-unifiedDataChannel.md#unifieddata) | 从DragEvent中获取拖拽相关数据。数据获取结果请参考错误码说明。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
| getSummary()10+ | [Summary](../../apis-arkdata/js-apis-data-unifiedDataChannel.md#summary) | 从DragEvent中获取拖拽相关数据的简介。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
| setResult(dragRect: [DragResult](#dragresult10枚举说明))10+ | void | 向DragEvent中设置拖拽结果。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
| getResult()10+ | [DragResult](#dragresult10枚举说明) | 从DragEvent中获取拖拽结果。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
| getPreviewRect()10+ | [Rectangle](ts-universal-attributes-touch-target.md#rectangle对象说明) | 获取拖拽跟手图相对于当前窗口的位置,以及跟手图尺寸信息,单位VP,其中x和y代表跟手图左上角的窗口坐标,width和height代表跟手图的尺寸。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
| getVelocityX()10+ | number | 获取当前拖拽的x轴方向拖动速度。坐标轴原点为屏幕左上角,单位为vp,分正负方向速度,从左往右为正,反之为负。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
| getVelocityY()10+ | number | 获取当前拖拽的y轴方向拖动速度。坐标轴原点为屏幕左上角,单位为vp,分正负方向速度,从上往下为正,反之为负。 |
| getVelocity()10+ | number | 获取当前拖拽的主方向拖动速度。为xy轴方向速度的平方和的算术平方根。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
| getWindowX()10+ | number | 当前拖拽点相对于窗口左上角的x轴坐标,单位为vp。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
| getWindowY()10+ | number | 当前拖拽点相对于窗口左上角的y轴坐标,单位为vp。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
| getDisplayX()10+ | number | 当前拖拽点相对于屏幕左上角的x轴坐标,单位为vp。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
| getDisplayY()10+ | number | 当前拖拽点相对于屏幕左上角的y轴坐标,单位为vp。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
| getX()(deprecated) | number | 当前拖拽点相对于窗口左上角的x轴坐标,单位为vp。
从API Version 10开始不再维护,建议使用getWindowX()代替。 |
| getY()(deprecated) | number | 当前拖拽点相对于窗口左上角的y轴坐标,单位为vp。
从API Version 10开始不再维护,建议使用getWindowY()代替。 |
| getModifierKeyState12+ | (Array<string>) => bool | 获取功能键按压状态。报错信息请参考以下错误码。支持功能键 'Ctrl'\|'Alt'\|'Shift'\|'Fn',设备外接带Fn键的键盘不支持Fn键查询。
**原子化服务API:** 从API version 13开始,该接口支持在原子化服务中使用。|
**错误码:**
以下错误码的详细介绍请参见[通用错误码](../../errorcode-universal.md)和[drag-event(拖拽事件)](../errorcode-drag-event.md)错误码。
| 错误码ID | 错误信息 |
| --------- | ------- |
| 401 | Parameter error. Possible causes: 1. Incorrect parameter types. 2. Parameter verification failed. |
| 190001 | Data not found.|
| 190002 | Data error. |
## DragResult10+枚举说明
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
| 名称 | 描述 |
| ----- | ----------------- |
| DRAG_SUCCESSFUL | 拖拽成功,在onDrop中使用。 |
| DRAG_FAILED | 拖拽失败,在onDrop中使用。 |
| DRAG_CANCELED | 拖拽取消,在onDrop中使用。 |
| DROP_ENABLED | 组件允许落入,在onDragMove中使用。 |
| DROP_DISABLED | 组件不允许落入,在onDragMove中使用。 |
## DragBehavior10+
当设置[DragResult](#dragresult10枚举说明)为DROP_ENABLED后,可设置DragBehavior为复制(copy)或剪切(move)。DragBehavior用来向开发者描述数据的处理方式是复制(copy)还是剪切(move),但无法最终决定对数据的实际处理方式。DragBehavior会通过onDragEnd带回给数据拖出方,发起拖拽的一方可通过DragBehavior来区分做出的是复制还是剪切数据的不同行为。
**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
| 名称 | 描述 |
| ----- | ----------------- |
| COPY | 指定对数据的处理方式为复制。|
| MOVE| 指定对数据的处理方式为剪切。|
## PreDragStatus12+枚举说明
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
**系统能力:** SystemCapability.ArkUI.ArkUI.Full
| 名称 | 值 | 描述 |
| ---- | - | ----------------- |
| ACTION_DETECTING_STATUS | 0 | 拖拽手势启动阶段。(按下50ms时触发) |
| READY_TO_TRIGGER_DRAG_ACTION | 1 | 拖拽准备完成,可发起拖拽阶段。(按下500ms时触发) |
| PREVIEW_LIFT_STARTED | 2 | 拖拽浮起动效发起阶段。(按下800ms时触发) |
| PREVIEW_LIFT_FINISHED | 3 | 拖拽浮起动效结束阶段。(浮起动效完全结束时触发) |
| PREVIEW_LANDING_STARTED | 4 | 拖拽落回动效发起阶段。(落回动效发起时触发) |
| PREVIEW_LANDING_FINISHED | 5 | 拖拽落回动效结束阶段。(落回动效结束时触发) |
| ACTION_CANCELED_BEFORE_DRAG | 6 | 拖拽浮起落位动效中断。(已满足READY_TO_TRIGGER_DRAG_ACTION状态后,未达到动效阶段,手指抬手时触发) |
## 示例
该示例展示了部分组件(如Image和Text等)拖拽和可落入区域的设置。
```ts
// xxx.ets
import { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData';
import { promptAction } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct Index {
@State targetImage: string = '';
@State targetText: string = 'Drag Text';
@State imageWidth: number = 100;
@State imageHeight: number = 100;
@State imgState: Visibility = Visibility.Visible;
@State abstractContent: string = "abstract";
@State textContent: string = "";
@State backGroundColor: Color = Color.Transparent;
@Builder
pixelMapBuilder() {
Column() {
Image($r('app.media.icon'))
.width(120)
.height(120)
.backgroundColor(Color.Yellow)
}
}
getDataFromUdmfRetry(event: DragEvent, callback: (data: DragEvent) => void) {
try {
let data: UnifiedData = event.getData();
if (!data) {
return false;
}
let records: Array = data.getRecords();
if (!records || records.length <= 0) {
return false;
}
callback(event);
return true;
} catch (e) {
console.log("getData failed, code = " + (e as BusinessError).code + ", message = " + (e as BusinessError).message);
return false;
}
}
getDataFromUdmf(event: DragEvent, callback: (data: DragEvent) => void) {
if (this.getDataFromUdmfRetry(event, callback)) {
return;
}
setTimeout(() => {
this.getDataFromUdmfRetry(event, callback);
}, 1500);
}
private PreDragChange(preDragStatus: PreDragStatus): void {
if (preDragStatus == PreDragStatus.READY_TO_TRIGGER_DRAG_ACTION) {
this.backGroundColor = Color.Red;
} else if (preDragStatus == PreDragStatus.ACTION_CANCELED_BEFORE_DRAG
|| preDragStatus == PreDragStatus.PREVIEW_LANDING_FINISHED) {
this.backGroundColor = Color.Blue;
}
}
build() {
Row() {
Column() {
Text('start Drag')
.fontSize(18)
.width('100%')
.height(40)
.margin(10)
.backgroundColor('#008888')
Image($r('app.media.icon'))
.width(100)
.height(100)
.draggable(true)
.margin({ left: 15 })
.visibility(this.imgState)
.onDragEnd((event) => {
// onDragEnd里取到的result值在接收方onDrop设置
if (event.getResult() === DragResult.DRAG_SUCCESSFUL) {
promptAction.showToast({ duration: 100, message: 'Drag Success' });
} else if (event.getResult() === DragResult.DRAG_FAILED) {
promptAction.showToast({ duration: 100, message: 'Drag failed' });
}
})
Text('test drag event')
.width('100%')
.height(100)
.draggable(true)
.margin({ left: 15 })
.copyOption(CopyOptions.InApp)
TextArea({ placeholder: 'please input words' })
.copyOption(CopyOptions.InApp)
.width('100%')
.height(50)
.draggable(true)
Search({ placeholder: 'please input you word' })
.searchButton('Search')
.width('100%')
.height(80)
.textFont({ size: 20 })
Column() {
Text('this is abstract')
.fontSize(20)
.width('100%')
}.margin({ left: 40, top: 20 })
.width('100%')
.height(100)
.onDragStart((event) => {
this.backGroundColor = Color.Transparent;
let data: unifiedDataChannel.PlainText = new unifiedDataChannel.PlainText();
data.abstract = 'this is abstract';
data.textContent = 'this is content this is content';
(event as DragEvent).setData(new unifiedDataChannel.UnifiedData(data));
})
.onPreDrag((status: PreDragStatus) => {
this.PreDragChange(status);
})
.backgroundColor(this.backGroundColor)
}.width('45%')
.height('100%')
Column() {
Text('Drag Target Area')
.fontSize(20)
.width('100%')
.height(40)
.margin(10)
.backgroundColor('#008888')
Image(this.targetImage)
.width(this.imageWidth)
.height(this.imageHeight)
.draggable(true)
.margin({ left: 15 })
.border({ color: Color.Black, width: 1 })
.allowDrop([uniformTypeDescriptor.UniformDataType.IMAGE])
.onDrop((dragEvent?: DragEvent) => {
this.getDataFromUdmf((dragEvent as DragEvent), (event: DragEvent) => {
let records: Array = event.getData().getRecords();
let rect: Rectangle = event.getPreviewRect();
this.imageWidth = Number(rect.width);
this.imageHeight = Number(rect.height);
this.targetImage = (records[0] as unifiedDataChannel.Image).imageUri;
event.useCustomDropAnimation = false;
this.imgState = Visibility.None;
// 显式设置result为successful,则将该值传递给拖出方的onDragEnd
event.setResult(DragResult.DRAG_SUCCESSFUL);
})
})
Text(this.targetText)
.width('100%')
.height(100)
.border({ color: Color.Black, width: 1 })
.margin(15)
.allowDrop([uniformTypeDescriptor.UniformDataType.PLAIN_TEXT])
.onDrop((dragEvent?: DragEvent) => {
this.getDataFromUdmf((dragEvent as DragEvent), (event: DragEvent) => {
let records: Array = event.getData().getRecords();
let plainText: unifiedDataChannel.PlainText = records[0] as unifiedDataChannel.PlainText;
this.targetText = plainText.textContent;
})
})
Column() {
Text(this.abstractContent).fontSize(20).width('100%')
Text(this.textContent).fontSize(15).width('100%')
}
.width('100%')
.height(100)
.margin(20)
.border({ color: Color.Black, width: 1 })
.allowDrop([uniformTypeDescriptor.UniformDataType.PLAIN_TEXT])
.onDrop((dragEvent?: DragEvent) => {
this.getDataFromUdmf((dragEvent as DragEvent), (event: DragEvent) => {
let records: Array = event.getData().getRecords();
let plainText: unifiedDataChannel.PlainText = records[0] as unifiedDataChannel.PlainText;
this.abstractContent = plainText.abstract as string;
this.textContent = plainText.textContent;
})
})
}.width('45%')
.height('100%')
.margin({ left: '5%' })
}
.height('100%')
}
}
```
