# 拖拽事件 拖拽事件是指在用户界面中,当用户拖动某个对象(如文件、控件或元素)时触发的一系列事件。这些事件允许开发者自定义拖拽行为,实现诸如拖放、调整位置等功能。 > **说明:** > > 从API version 8开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 > > 应用本身预置的资源文件(即应用在安装前的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)、[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](ts-universal-attributes-drag-drop.md#draggable)属性设置为true,并在[onDragStart](ts-universal-events-drag-drop.md#ondragstart)等接口中实现数据传输相关内容,才能正确处理拖拽能力。 > **说明:** > > Text组件需配合[copyOption](ts-basic-components-text.md#copyoption9)一起使用,设置copyOptions为CopyOptions.InApp或者CopyOptions.LocalDevice。 ## onDragStart onDragStart(event: (event: DragEvent, extraParams?: string) => CustomBuilder | DragItemInfo): T 第一次拖拽此事件绑定的组件时,长按时间 >= 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](#dragevent7), extraParams?: string) => [CustomBuilder](ts-types.md#custombuilder8)  \|  [DragItemInfo](#dragiteminfo) | 是 | 回调函数。
**说明:**
event参数为拖拽事件的信息。
extraParams参数为拖拽事件的额外信息,需要解析为JSON格式,参考[extraParams](#extraparams说明)说明。
CustomBuilder为拖拽过程中显示的组件信息,不支持全局builder。| **返回值:** | 类型 | 说明 | | -------- | -------- | | T | 返回当前组件。 | ## onDragEnter onDragEnter(event: (event: DragEvent, extraParams?: string) => void): T 拖拽进入组件范围内时,触发回调,当监听了[onDrop](#ondrop)事件时,此事件才有效。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **参数:** | 参数名 | 类型 | 必填 | 说明 | | ----------- | ------------------------------- | ---- | ------------------------------ | | event | (event: [DragEvent](#dragevent7), extraParams?: string) => void | 是 | 回调函数。
**说明:**
event为拖拽事件信息,包括拖拽点坐标。
extraParams为拖拽事件额外信息,需要解析为Json格式,参考[extraParams](#extraparams说明)说明。| **返回值:** | 类型 | 说明 | | -------- | -------- | | T | 返回当前组件。 | ## onDragMove onDragMove(event: (event: DragEvent, extraParams?: string) => void): T 拖拽在组件范围内移动时,触发回调,当监听了[onDrop](#ondrop)事件时,此事件才有效。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **参数:** | 参数名 | 类型 | 必填 | 说明 | | ----------- | ------------------------------- | ---- | ------------------------------ | | event | (event: [DragEvent](#dragevent7), extraParams?: string) => void | 是 | 回调函数。
**说明:**
event为拖拽事件信息,包括拖拽点坐标。
extraParams为拖拽事件额外信息,需要解析为Json格式,参考[extraParams](#extraparams说明)说明。| **返回值:** | 类型 | 说明 | | -------- | -------- | | T | 返回当前组件。 | ## onDragLeave onDragLeave(event: (event: DragEvent, extraParams?: string) => void): T 拖拽离开组件范围内时,触发回调,当监听了[onDrop](#ondrop)事件时,此事件才有效。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **参数:** | 参数名 | 类型 | 必填 | 说明 | | ----------- | ------------------------------- | ---- | ------------------------------ | | event | (event: [DragEvent](#dragevent7), extraParams?: string) => void | 是 | 回调函数。
**说明:**
event为拖拽事件信息,包括拖拽点坐标。
extraParams为拖拽事件额外信息,需要解析为Json格式,参考[extraParams](#extraparams说明)说明。| **返回值:** | 类型 | 说明 | | -------- | -------- | | T | 返回当前组件。 | ## onDrop onDrop(event: (event: DragEvent, extraParams?: string) => void): T 绑定此事件的组件可作为释放目标。当在本组件范围内停止拖放行为时,将触发回调。如果开发者未在onDrop中主动调用event.setResult()来设置拖拽接收的结果,对于系统支持的默认可拖入组件,处理结果将以系统实际处理的数据为准。对于其他组件,系统将默认视为数据接收成功。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **参数:** | 参数名 | 类型 | 必填 | 说明 | | ----------- | ------------------------------- | ---- | ------------------------------ | | event | (event: [DragEvent](#dragevent7), extraParams?: string) => void | 是 | 回调函数。
**说明:**
event为拖拽事件信息,包括拖拽点坐标。
extraParams为拖拽事件额外信息,需要解析为Json格式,参考[extraParams](#extraparams说明)说明。| **返回值:** | 类型 | 说明 | | -------- | -------- | | T | 返回当前组件。 | ## onDrop15+ onDrop(eventCallback: OnDragEventCallback, dropOptions?: DropOptions): T 绑定此事件的组件可作为拖拽释放目标,当在本组件范围内停止拖拽行为时,触发回调。如果开发者没有在onDrop中主动调用event.setResult()设置拖拽接收的结果,若拖拽组件为系统支持默认拖入的组件,以系统实际处理数据结果为准,其它组件则系统按照数据接收成功处理。 **原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **参数:** | 参数名 | 类型 | 必填 | 说明 | | ----------- | ------------------------------- | ---- | ------------------------------ | | eventCallback | [OnDragEventCallback](#ondrageventcallback15) | 是 | 回调函数。| | dropOptions | [DropOptions](#dropoptions15) | 否 | 落入过程的参数。 | **返回值:** | 类型 | 说明 | | -------- | -------- | | T | 返回当前组件。 | ## onDragEnd10+ onDragEnd(event: (event: DragEvent, extraParams?: string) => void): T 绑定此事件的组件触发的拖拽结束后,触发回调。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **参数:** | 参数名 | 类型 | 必填 | 说明 | | ----------- | ------------------------------- | ---- | ------------------------------ | | event | (event: [DragEvent](#dragevent7), extraParams?: string) => void | 是 | 回调函数。
**说明:**
event为拖拽事件信息,在onDragEnd调用中不包括拖拽点坐标。
extraParams为拖拽事件额外信息,需要解析为Json格式,参考[extraParams](#extraparams说明)说明。| **返回值:** | 类型 | 说明 | | -------- | -------- | | T | 返回当前组件。 | ## onPreDrag12+ onPreDrag(callback: Callback\): T 绑定此事件的组件,当处于拖拽发起前的不同阶段时,触发回调。 **原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **参数:** | 参数名 | 类型 | 必填 | 说明 | | ----------- | ------------------------------- | ---- | ------------------------------ | | callback | Callback<[PreDragStatus](#predragstatus12枚举说明)> | 是 | 回调函数。| **返回值:** | 类型 | 说明 | | -------- | -------- | | T | 返回当前组件。 | ## onDragSpringLoading20+ onDragSpringLoading(callback: Callback\ | null, configuration?: DragSpringLoadingConfiguration): T 绑定此事件的组件可作为具有悬停检测功能的拖拽响应目标。当拖拽对象悬停在目标上时,触发回调通知。此时只有一个目标可以成为响应方,并且子组件始终具有更高的响应优先级。 关于悬停检测的触发机制及详细使用方法,请参考开发指南[支持悬停检测](../../../ui/arkts-common-events-drag-event.md#支持悬停检测)。 **原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **参数:** | 参数名 | 类型 | 必填 | 说明 | | :------------ | ----------------------------------------- | ---- | ---------------------------------------------- | | callback | Callback\<[SpringLoadingContext](#springloadingcontext20)\> \| null | 是 | 悬停检测回调函数,当值为null时禁用悬停检测。 | | configuration | [DragSpringLoadingConfiguration](../js-apis-arkui-dragController.md#dragspringloadingconfiguration20) | 否 | 悬停检测配置信息,为undefined时取[DragSpringLoadingConfiguration](../js-apis-arkui-dragController.md#dragspringloadingconfiguration20)默认值。 | **返回值:** | 类型 | 说明 | | -------- | -------- | | T | 返回当前组件。 | ## DragItemInfo **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full | 名称 | 类型 | 只读| 可选 | 说明 | | --------- | ---------------------------------------- | ---- | ---- | --------------------------------- | | pixelMap | [PixelMap](../../apis-image-kit/arkts-apis-image-PixelMap.md) | 否 | 是 |设置拖拽过程中显示的图片。 | | 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 | 否 | 是 |拖拽项的附加信息,用于描述拖拽项。 | ## PreviewConfiguration15+ 配置自定义拖拽过程中的预览图样式。 **原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full | 名称 | 类型 | 只读 | 可选 | 说明 | | ---------- | ---- | ---- | ---- | ------------------------------------------------------------ | | onlyForLifting | boolean | 否 | 是 | 自定义配置的预览图是否仅用于浮起。
**说明:**
默认值为false。true表示自定义预览图仅用于浮起,false表示可用于浮起和拖拽。设置为true时,如果发起长按拖拽,浮起时的预览图为自定义配置的预览图,拖拽时的预览图不使用[dragPreview](ts-universal-attributes-drag-drop.md#dragpreview11)属性,优先使用开发者在[onDragStart](ts-universal-events-drag-drop.md#ondragstart)中返回的预览图,如果[onDragStart](ts-universal-events-drag-drop.md#ondragstart)中没有返回预览图则使用组件自截图。| | delayCreating | boolean | 否 | 是 | 组件预览builder是否在设置时加载。
默认值为false。true表示组件预览builder在设置时加载,false表示组件预览builder不在设置时加载。| ## extraParams说明 用于返回组件在拖拽中需要用到的额外信息。 extraParams是Json对象转换的string字符串,可以通过Json.parse转换的Json对象获取如下属性。 | 名称 | 类型 | 描述 | | ------------- | ------ | ---------------------------------------- | | selectedIndex | number | 当拖拽事件设在父容器的子元素时,selectedIndex表示当前被拖拽子元素是父容器第selectedIndex个子元素,selectedIndex从0开始。
仅在ListItem组件的拖拽事件中生效。 | | insertIndex | number | 当前拖拽元素在List组件中放下时,insertIndex表示被拖拽元素插入该组件的第insertIndex个位置,insertIndex从0开始。
仅在List组件的拖拽事件中生效。 | ## DragEvent7+ **系统能力:** SystemCapability.ArkUI.ArkUI.Full ### 属性 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full | 名称 | 类型 | 只读 | 可选 | 说明 | | ------ | ------ | ----- | ---- | ------- | | useCustomDropAnimation10+ | boolean | 否 | 否 |当拖拽结束时,是否禁用系统默认落位动效。
应用可将该值设定为true来禁用系统默认落位动效,并实现自己的自定义落位动效。
当不配置或设置为false时,系统默认落位动效生效,当[setResult](#setresult10)设置为DRAG_SUCCESSFUL时,落位为缩小消失动效,不为DRAG_SUCCESSFUL时,则为放大消失动效。
当未禁用系统默认落位动效时,应用不应再实现自定义动效,以避免动效上的冲突。
默认值:false | |dragBehavior10+ | [DragBehavior](#dragbehavior10) | 否 | 否 |切换复制和剪贴模式的角标显示状态。
默认值:DragBehavior.COPY。 | ### setData10+ setData(unifiedData: UnifiedData): void 向DragEvent中设置用于拖拽的数据。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **参数:** | 参数名 | 类型 | 必填 | 说明 | | ----------- | ------------------------------------------------------------ | ---- | ---------------- | | unifiedData | [UnifiedData](#unifieddata10) | 是 | 拖拽相关的数据。 | ### getData10+ getData(): UnifiedData 获取拖拽相关数据。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------------------------------------------------------------ | ------------------------------------------------------------ | | [UnifiedData](../../apis-arkdata/js-apis-data-unifiedDataChannel.md#unifieddata) | 从DragEvent中获取拖拽相关数据。数据获取结果请参考错误码说明。 | **错误码:** 以下错误码的详细介绍请参见[drag-event(拖拽事件)](../errorcode-drag-event.md)错误码。 | 错误码ID | 错误信息 | | --------- | ------- | | 190001 | Data not found.| | 190002 | Data error. | ### getSummary10+ getSummary(): Summary 获取所拖拽数据的概要,包括数据类型及大小信息;在延迟拖拽场景下,只能获取到数据类型信息。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------------------------------------------------------------ | ------------------------------------- | | [Summary](#summary10) | 拖拽相关数据的概要。 | ### setResult10+ setResult(dragResult: DragResult): void 在DragEvent中设置拖拽结果。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **参数:** | 参数名 | 类型 | 必填 | 说明 | | ---------- | ----------------------------------- | ---- | ---------- | | dragResult | [DragResult](#dragresult10枚举说明) | 是 | 拖拽结果。 | ### getResult10+ getResult(): DragResult 获取拖拽结果。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ----------------------------------- | ----------------------------- | | [DragResult](#dragresult10枚举说明) | 从DragEvent中获取的拖拽结果。 | ### getPreviewRect10+ getPreviewRect(): Rectangle 获取拖拽预览图相对于当前窗口的位置,以及预览图尺寸信息。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------------------------------------------------------------ | ------------------------------------------------------------ | | [Rectangle](ts-universal-attributes-touch-target.md#rectangle对象说明) | 拖拽预览图相对于当前窗口的位置,以及预览图尺寸信息,单位vp,其中x和y代表预览图左上角的窗口坐标,width和height代表预览图的尺寸。 | ### getVelocityX10+ getVelocityX(): number 获取当前拖拽的x轴方向拖动速度。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------ | ------------------------------------------------------------ | | number | 当前拖拽的x轴方向拖动速度。坐标轴原点为屏幕左上角,单位为vp,分正负方向速度,从左往右为正,反之为负。 | ### getVelocityY10+ getVelocityY(): number 获取当前拖拽的y轴方向拖动速度。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------ | ------------------------------------------------------------ | | number | 当前拖拽的y轴方向拖动速度。坐标轴原点为屏幕左上角,单位为vp,分正负方向速度,从上往下为正,反之为负。 | ### getVelocity10+ getVelocity(): number 获取当前拖拽的主方向拖动速度。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------ | ------------------------------------------------------------ | | number | 当前拖拽的主方向拖动速度。为xy轴方向速度的平方和的算术平方根,单位为vp。 | ### getWindowX10+ getWindowX(): number 获取拖拽点相对于窗口左上角的x轴坐标。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------ | ----------------------------------------------- | | number | 当前拖拽点相对于窗口左上角的x轴坐标,单位为vp。 | ### getWindowY10+ getWindowY(): number 获取拖拽点相对于窗口左上角的y轴坐标。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------ | ----------------------------------------------- | | number | 当前拖拽点相对于窗口左上角的y轴坐标,单位为vp。 | ### getDisplayX10+ getDisplayX(): number 获取当前拖拽点相对于屏幕左上角的x轴坐标。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------ | ----------------------------------------------- | | number | 当前拖拽点相对于屏幕左上角的x轴坐标,单位为vp。 | ### getDisplayY10+ getDisplayY(): number 获取当前拖拽点相对于屏幕左上角的y轴坐标。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------ | ----------------------------------------------- | | number | 当前拖拽点相对于屏幕左上角的y轴坐标,单位为vp。 | ### getModifierKeyState12+ getModifierKeyState?(keys: Array): boolean 获取功能键按压状态。 **原子化服务API:** 从API version 13开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full | 参数名 | 类型 | 必填 | 说明 | | ------ | ------------------- | ---- | ------------------------------------------------------------ | | keys | Array<string> | 是 | 获取功能键按压状态。报错信息请参考以下错误码。支持功能键 'Ctrl'\| 'Alt' \| 'Shift'。
**说明:**
此接口不支持在手写笔场景下使用。 | **错误码:** 以下错误码的详细介绍请参见[通用错误码](../../errorcode-universal.md)。 | 错误码ID | 错误信息 | | --------- | ------- | | 401 | Parameter error. Possible causes: 1. Incorrect parameter types. 2. Parameter verification failed. | **返回值:** | 类型 | 说明 | | ------- | ----------------------------------------------------- | | boolean | 是否被按下,返回true表示被按下,返回false表示未被按下 | ### startDataLoading15+ startDataLoading(options: DataSyncOptions): string 异步获取拖拽数据,并通知开发者当前数据同步进度,仅支持在onDrop阶段使用。 **原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **参数:** | 参数名 | 类型 | 必填 | 说明 | | ------- | ------------------------------------- | ---- | ------------------------------------------------------------ | | options | [DataSyncOptions](#datasyncoptions15) | 是 | 获取拖拽数据时的参数,包含目标路径、文件冲突选项、进度条类型等。数据传输过程中可使用[cancelDataLoading](../arkts-apis-uicontext-dragcontroller.md#canceldataloading15)接口取消数据加载。 | **错误码:** 以下错误码的详细介绍请参见[通用错误码](../../errorcode-universal.md)和[drag-event(拖拽事件)](../errorcode-drag-event.md)错误码。 | 错误码ID | 错误信息 | | --------- | ------- | | 401 | Parameter error. | | 190003 | Operation not allowed for current phase. | **返回值:** | 类型 | 说明 | | ------ | ---------------------------------- | | string | 拖拽数据的标识,用于区分每次拖拽。 | ### executeDropAnimation18+ executeDropAnimation(customDropAnimation: Callback\): void 设置自定义落位动效的执行函数,仅在useCustomDropAnimation为true时有效。 **原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **参数:** | 参数名 | 类型 | 必填 | 说明 | | ------ | ------ | --- | --------- | | customDropAnimation | [Callback\](../../../reference/apis-basic-services-kit/js-apis-base.md#callback) | 是 |在此回调函数中实现自定义落位动效。
**说明:**
1. 该接口仅在onDrop回调中使用有效。
2. 使用前需设置useCustomDropAnimation为true,否则该接口不生效。
3. 不要在动画callback中实现与动效无关的逻辑,避免影响执行效率。| ### getDisplayId20+ getDisplayId(): number 获取当前拖拽事件发生时所在的屏幕ID,不支持当eventType为NODE_ON_DRAG_END时获取。 **原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------ | -------------------------------- | | number | 当前拖拽事件发生时所在的屏幕ID。 | ### getDragSource20+ getDragSource(): string 获取拖起方包名。 **原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------ | -------------- | | string | 拖起方的包名。 | ### isRemote20+ isRemote(): boolean 获取是否是跨设备拖拽,跨设备拖拽时为true。 **原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------- | ------------------------------------------------------------ | | boolean | 是否是跨设备拖拽,返回true表示是跨设备拖拽,返回false表示不是跨设备拖拽。 | ### setDataLoadParams20+ setDataLoadParams(dataLoadParams: DataLoadParams): void 设置起拖方延迟提供数据。使用此方法向系统提供数据加载参数,而不是直接提供完整的数据对象。当用户在目标应用程序上落入时,系统将使用此参数从起拖方请求实际数据。与[setData](#setdata10)方法同时使用,以最后调用的方法为准。该接口仅在[onDragStart](ts-universal-events-drag-drop.md#ondragstart)回调中生效。 **原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **参数:** | 参数名 | 类型 | 必填 | 说明 | | -------| -------| ------- | ------------------------------------------------------------ | | dataLoadParams | [DataLoadParams](#dataloadparams20) | 是 | 落入操作时使用的数据加载参数。 | ### getX(deprecated) getX(): number 当前拖拽点相对于窗口左上角的x轴坐标,单位为vp。从API version 10开始不再维护,建议使用[getWindowX()](#getwindowx10)代替。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------ | --------------------------------------------------- | | number | 返回当前拖拽点相对于窗口左上角的x轴坐标。
单位:vp | ### getY(deprecated) getY(): number 当前拖拽点相对于窗口左上角的y轴坐标,单位为vp。从API version 10开始不再维护,建议使用[getWindowY()](#getwindowy10)代替。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------ | --------------------------------------------------- | | number | 返回当前拖拽点相对于窗口左上角的y轴坐标。
单位:vp | ### getGlobalDisplayX20+ getGlobalDisplayX(): number 当前拖拽点相对于全局屏幕的左上角的X坐标。 **原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------ | --------------------------------------------------- | | number | 返回当前拖拽点相对于全局屏幕的左上角的X坐标。
单位:vp,取值范围:[0, +∞)| ### getGlobalDisplayY20+ getGlobalDisplayY(): number 当前拖拽点相对于全局屏幕的左上角的Y坐标。 **原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full **返回值:** | 类型 | 说明 | | ------ | --------------------------------------------------- | | number | 返回当前拖拽点相对于全局屏幕的左上角的Y坐标。
单位:vp,取值范围:[0, +∞)| ## DragResult10+枚举说明 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full | 名称 | 值 | 说明 | | ----- | -- | --------------- | | DRAG_SUCCESSFUL | 0 |拖拽成功,在[onDrop](#ondrop)中使用。 | | DRAG_FAILED | 1 |拖拽失败,在[onDrop](#ondrop)中使用。 | | DRAG_CANCELED | 2 |拖拽取消,在[onDrop](#ondrop)中使用。 | | DROP_ENABLED | 3 |组件允许落入,在[onDragEnter](#ondragenter),[onDragMove](#ondragmove),[onDragLeave](#ondragleave)中使用。 | | DROP_DISABLED | 4 |组件不允许落入,在[onDragEnter](#ondragenter),[onDragMove](#ondragmove),[onDragLeave](#ondragleave)中使用。 | ## DragBehavior10+ 当设置[DragResult](#dragresult10枚举说明)为DROP_ENABLED后,可设置DragBehavior为复制(COPY)或剪切(MOVE)。DragBehavior用来向开发者描述数据的处理方式是复制(COPY)还是剪切(MOVE),但无法最终决定对数据的实际处理方式。DragBehavior会通过onDragEnd带回给数据拖出方,发起拖拽的一方可通过DragBehavior来区分做出的是复制(COPY)还是剪切(MOVE)数据的不同行为。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full | 名称 | 值 | 说明 | | ----- | -- | ----------------- | | COPY | - |指定对数据的处理方式为复制。| | MOVE| - |指定对数据的处理方式为剪切。| ## PreDragStatus12+枚举说明 **系统能力:** SystemCapability.ArkUI.ArkUI.Full | 名称 | 值 | 说明 | | ---- | - | ----------------- | | ACTION_DETECTING_STATUS | 0 | 拖拽手势启动阶段。(按下50ms时触发)
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 | | READY_TO_TRIGGER_DRAG_ACTION | 1 | 拖拽准备完成,可发起拖拽阶段。(按下500ms时触发)
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 | | PREVIEW_LIFT_STARTED | 2 | 拖拽浮起动效发起阶段。(按下800ms时触发)
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 | | PREVIEW_LIFT_FINISHED | 3 | 拖拽浮起动效结束阶段。(浮起动效完全结束时触发)
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 | | PREVIEW_LANDING_STARTED | 4 | 拖拽落回动效发起阶段。(落回动效发起时触发)
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 | | PREVIEW_LANDING_FINISHED | 5 | 拖拽落回动效结束阶段。(落回动效结束时触发)
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 | | ACTION_CANCELED_BEFORE_DRAG | 6 | 拖拽浮起落位动效中断。(已满足READY_TO_TRIGGER_DRAG_ACTION状态后,未达到动效阶段,手指抬手时触发)
**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 | | PREPARING_FOR_DRAG_DETECTION18+ | 7 | 拖拽准备完成,可发起拖拽阶段。(按下350ms时触发)
**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。 | ## UnifiedData10+ type UnifiedData = UnifiedData 拖拽相关的数据。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full | 类型 | 说明 | | ----- | ----------------- | | [UnifiedData](../../apis-arkdata/js-apis-data-unifiedDataChannel.md#unifieddata) | 拖拽相关的数据。| ## Summary10+ type Summary = Summary 拖拽相关数据的简介。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full | 类型 | 说明 | | ----- | ----------------- | | [Summary](../../apis-arkdata/js-apis-data-unifiedDataChannel.md#summary) | 拖拽相关数据的简介。| ## DataLoadParams20+ type DataLoadParams = DataLoadParams 落入操作时使用的数据加载参数。 **原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full | 类型 | 说明 | | ----- | ----------------- | | [DataLoadParams](../../apis-arkdata/js-apis-data-unifiedDataChannel.md#dataloadparams20) | 落入操作时使用的数据加载参数。| ## DataSyncOptions15+ type DataSyncOptions = GetDataParams 作为startDataLoading的入参对象。 **原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full | 类型 | 说明 | | ----- | ----------------- | | [GetDataParams](../../apis-arkdata/js-apis-data-unifiedDataChannel.md#getdataparams15) | 表示从UDMF获取数据时的参数,包含目标路径、文件冲突选项、进度条类型等。| ## OnDragEventCallback15+ type OnDragEventCallback = (event: DragEvent, extraParams?: string) => void 拖拽事件的回调函数。 **原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full | 参数名 | 类型 |必填 |说明 | | ----- | ----------------- | ----- | ----- | | event | [DragEvent](#dragevent7)| 是 | event为拖拽事件信息,包括拖拽点坐标。| | extraParams| string |否 | extraParams为拖拽事件额外信息,需要解析为Json格式,参考[extraParams](#extraparams说明)说明。| ## DropOptions15+ 设置落入过程的参数。 **原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full | 名称 | 类型 | 只读 | 可选 | 说明 | | ------ | ------ | ---------------- | ------ | ------ | | disableDataPrefetch | boolean | 否 | 否 | 设置拖拽是否提前获取数据。true表示不提前获取数据,false表示提前获取数据,默认值为false。
**说明:**
当使用[startDataLoading](#startdataloading15)获取数据时需设置该参数为true,防止拖拽提前获取数据。 | ## DragSpringLoadingConfiguration20+ type DragSpringLoadingConfiguration = DragSpringLoadingConfiguration 定义拖拽的悬停检测配置参数的接口。 **原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full | 类型 | 说明 | | ----- | ----------------- | | [DragSpringLoadingConfiguration](../js-apis-arkui-dragController.md#dragspringloadingconfiguration20) | 定义拖拽的悬停检测配置参数的接口。| ## SpringLoadingContext20+ type SpringLoadingContext = SpringLoadingContext 定义回调上下文信息的类,用于在悬停检测回调中传递给应用程序,使其能访问拖拽状态。 **原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。 **系统能力:** SystemCapability.ArkUI.ArkUI.Full | 类型 | 说明 | | ----- | ----------------- | | [SpringLoadingContext](../js-apis-arkui-dragController.md#springloadingcontext20) | 定义回调上下文信息的类,用于在悬停检测回调中传递给应用程序,以便应用程序能访问拖拽状态。| ## 示例 ### 示例1(设置组件拖拽和落入) 示例1展示了部分组件(如Image和Text等)拖拽和可落入区域的设置。 ```ts // xxx.ets import { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData'; 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.error("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) { this.getUIContext().getPromptAction().showToast({ duration: 100, message: 'Drag Success' }); } else if (event.getResult() === DragResult.DRAG_FAILED) { this.getUIContext().getPromptAction().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%') } } ``` ![events-drag-drop](figures/events-drag-drop.png) ### 示例2(自定义落位动效) 示例2展示了通过自定义接口executeDropAnimation,实现落位动效。 ```ts import { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData'; @Entry @Component struct DropAnimationExample { @State targetImage: string = ''; @State targetText: string = 'Drag Text'; @State hyperLinkText: string = 'HyperLink'; @State hyperLinkContent: string = 'HyperLink'; @State imageWidth: number = 100; @State imageHeight: number = 100; @State imgState: Visibility = Visibility.Visible; @State videoSrc: string = 'resource://RAWFILE/02.mp4'; @State abstractContent: string = "abstract"; @State textContent: string = ""; customDropAnimation = () => { this.getUIContext().animateTo({ duration: 1000, curve: Curve.EaseOut, playMode: PlayMode.Normal }, () => { this.imageWidth = 200; this.imageHeight = 200; this.imgState = Visibility.None; }) } build() { Row() { Column() { Image($r('app.media.app_icon')) .width(100) .height(100) .draggable(true) .margin({ left: 15 ,top: 40}) .visibility(this.imgState) .onDragStart((event) => { }) .onDragEnd((event) => { if (event.getResult() === DragResult.DRAG_SUCCESSFUL) { console.info('Drag Success'); } else if (event.getResult() === DragResult.DRAG_FAILED) { console.error('Drag failed'); } }) }.width('45%') .height('100%') Column() { Text('Drag Target Area') .fontSize(20) .width(180) .height(40) .textAlign(TextAlign.Center) .margin(10) .backgroundColor('rgb(240,250,255)') Column() { 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) => { let records: Array = dragEvent.getData().getRecords(); let rect: Rectangle = dragEvent.getPreviewRect(); this.imageWidth = Number(rect.width); this.imageHeight = Number(rect.height); this.targetImage = (records[0] as unifiedDataChannel.Image).imageUri; dragEvent.useCustomDropAnimation = true; dragEvent.executeDropAnimation(this.customDropAnimation) }) .width(this.imageWidth) .height(this.imageHeight) }.width('45%') .height('100%') .margin({ left: '5%' }) } .height('100%') } } ``` ![executeDropAnimation](figures/executeDropAnimation.gif) ### 示例3(拖拽异步获取数据) 示例3展示了通过startDataLoading实现拖拽异步获取数据。 ```ts import { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData'; import { fileUri, fileIo as fs } from '@kit.CoreFileKit'; import { common } from '@kit.AbilityKit'; @Entry @Component struct ImageExample { @State uri: string = ""; @State blockArr: string[] = []; uiContext = this.getUIContext(); udKey: string = ''; build() { Column() { Text('Image拖拽') .fontSize('30dp') Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceAround }) { Image($r('app.media.startIcon')) .width(100) .height(100) .border({ width: 1 }) .draggable(true) .onDragStart((event:DragEvent) => { const context: Context|undefined = this.uiContext.getHostContext(); if(context) { let data = context.resourceManager.getMediaContentSync($r('app.media.startIcon').id, 120); const arrayBuffer: ArrayBuffer = data.buffer.slice(data.byteOffset, data.byteLength + data.byteOffset); let filePath = context.filesDir + '/test.png'; let file = fs.openSync(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE); fs.writeSync(file.fd, arrayBuffer); //获取图片的uri let uri = fileUri.getUriFromPath(filePath); let image: unifiedDataChannel.Image = new unifiedDataChannel.Image(); image.imageUri = uri; let dragData: unifiedDataChannel.UnifiedData = new unifiedDataChannel.UnifiedData(image); (event as DragEvent).setData(dragData); } }) } .margin({ bottom: 20 }) Row() { Column(){ Text('可释放区域') .fontSize('15dp') .height('10%') List(){ ForEach(this.blockArr, (item:string, index) => { ListItem() { Image(item) .width(100) .height(100) .border({width: 1}) } .margin({ left: 30 , top : 30}) }, (item:string) => item) } .border({width: 1}) .height('90%') .width('100%') .onDrop((event?: DragEvent, extraParams?: string) => { console.info("enter onDrop") let context = this.uiContext.getHostContext() as common.UIAbilityContext; let pathDir: string = context.distributedFilesDir; let destUri = fileUri.getUriFromPath(pathDir); let progressListener: unifiedDataChannel.DataProgressListener = (progress: unifiedDataChannel.ProgressInfo, dragData: UnifiedData|null) => { if(dragData != null) { let arr:Array = dragData.getRecords(); if(arr.length > 0) { if (arr[0].getType() === uniformTypeDescriptor.UniformDataType.IMAGE) { let image = arr[0] as unifiedDataChannel.Image; this.uri = image.imageUri; this.blockArr.splice(JSON.parse(extraParams as string).insertIndex, 0, this.uri); } } else { console.info('dragData arr is null'); } } else { console.info('dragData is undefined'); } console.info(`percentage: ${progress.progress}`); }; let options: DataSyncOptions = { destUri: destUri, fileConflictOptions: unifiedDataChannel.FileConflictOptions.OVERWRITE, progressIndicator: unifiedDataChannel.ProgressIndicator.DEFAULT, dataProgressListener: progressListener, } try { this.udKey = (event as DragEvent).startDataLoading(options); console.info('udKey: ', this.udKey); } catch(e) { console.error(`startDataLoading errorCode: ${e.code}, errorMessage: ${e.message}`); } }, {disableDataPrefetch: true}) } .height("50%") .width("90%") .border({ width: 1 }) } Button('取消数据传输') .onClick(() => { try { this.getUIContext().getDragController().cancelDataLoading(this.udKey); } catch (e) { console.error(`cancelDataLoading errorCode: ${e.code}, errorMessage: ${e.message}`); } }) .margin({top: 10}) }.width('100%') } } ``` ### 示例4(获取当前拖拽的屏幕ID) 示例4展示了通过onDragXXX(不支持onDragEnd)接口获取到拖拽事件,并调用拖拽事件里的getDisplayId接口获取屏幕ID。 ```ts import { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData'; import { BusinessError } from '@kit.BasicServicesKit'; @Entry @Component struct Index { @State targetImage: string = ''; @State imageWidth: number = 100; @State imageHeight: number = 100; @State imgState: Visibility = Visibility.Visible; @State backGroundColor: Color = Color.Transparent; @State startDisplayId: number = -1; @State enterDisplayId: number = -1; @State moveDisplayId: number = -1; @State leaveDisplayId: number = -1; @State dropDisplayId: number = -1; @Builder pixelMapBuilder() { Column() { Image($r('app.media.app_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.error("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.startIcon')) .width(100) .height(100) .draggable(true) .margin({ left: 15 }) .visibility(this.imgState) .onDragStart((event) => { let id = event.getDisplayId(); this.startDisplayId = id; }) .onDragEnd((event) => { if (event.getResult() === DragResult.DRAG_SUCCESSFUL) { this.getUIContext().getPromptAction().showToast({ duration: 100, message: 'Drag Success' }); } else if (event.getResult() === DragResult.DRAG_FAILED) { this.getUIContext().getPromptAction().showToast({ duration: 100, message: 'Drag failed' }); } }) Text('displayID in onDragStart: ' + this.startDisplayId.toString()) .width('100%') .height(50) .draggable(true) .margin({ left: 15 }) Text('displayID in onDragEnter: ' + this.enterDisplayId.toString()) .width('100%') .height(50) .draggable(true) .margin({ left: 15 }) Text('displayID in onDragMove: ' + this.moveDisplayId.toString()) .width('100%') .height(50) .draggable(true) .margin({ left: 15 }) Text('displayID in onDragLeave: ' + this.leaveDisplayId.toString()) .width('100%') .height(50) .draggable(true) .margin({ left: 15 }) Text('displayID in onDrop: ' + this.dropDisplayId.toString()) .width('100%') .height(50) .draggable(true) .margin({ left: 15 }) .onPreDrag((status: PreDragStatus) => { this.PreDragChange(status); }) }.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]) .onDragEnter((event) => { let id = event.getDisplayId(); this.enterDisplayId = id; }) .onDragMove((event) => { let id = event.getDisplayId(); this.moveDisplayId = id; }) .onDragLeave((event) => { let id = event.getDisplayId(); this.leaveDisplayId = id; }) .onDrop((dragEvent: DragEvent) => { let id = dragEvent.getDisplayId(); this.dropDisplayId = id; 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; event.setResult(DragResult.DRAG_SUCCESSFUL); }) }) }.width('45%') .height('100%') .margin({ left: '5%' }) } .height('100%') } } ``` ![DragEvent_getDisplayId](figures/DragEvent_getDisplayId.png) ### 示例5(获取包名和是否是跨设备) 示例5展示了通过onDragXXX接口获取到拖拽事件,调用拖拽事件里的getDragSource接口获取包名,调用isRemote接口获取是否是跨设备。 ```ts @Entry @Component struct Index { @State targetImage: string = ''; @State startDragSource: string = ''; @State startIsRemote: boolean = true; @State enterDragSource: string = ''; @State enterIsRemote: boolean = true; build() { Column() { Row() { Column() { Text('start Drag Area') .fontSize(18) .width('100%') .height(40) .margin(10) .backgroundColor('#008888') Image($r('app.media.startIcon')) .onDragStart((event) => { this.startDragSource = (event as DragEvent).getDragSource(); this.startIsRemote = (event as DragEvent).isRemote(); }) .width(100) .height(100) .draggable(true) .margin({ left: 15 }) } .border({ color: Color.Black, width: 1 }) .width('45%') .height('50%') Column() { Text('Drag Target Area') .fontSize(20) .width('100%') .height(40) .margin(10) .backgroundColor('#008888') Image(this.targetImage) .width(100) .height(100) .draggable(true) .margin({ left: 15 }) .border({ color: Color.Black, width: 1 }) .onDragEnter((event) => { this.enterDragSource = (event as DragEvent).getDragSource(); this.enterIsRemote = (event as DragEvent).isRemote(); }) .onDrop(()=>{}) } .border({ color: Color.Black, width: 1 }) .width('45%') .height('50%') .margin({ left: '5%' }) } .height('70%') Text('onDragStart dragSource: ' + this.startDragSource.toString() + '\n' + 'onDragStart isRemote: ' + this.startIsRemote.toString()) .width('100%') .height(50) .margin({ left: 15 }) Text('onDragEnter dragSource: ' + this.enterDragSource.toString() + '\n' + 'onDragEnter isRemote: ' + this.enterIsRemote.toString()) .width('100%') .height(50) .margin({ left: 15 }) } } } ``` ![dragSourceAndIsRemote](figures/dragSourceAndIsRemote.png) ### 示例6(拖拽支持悬停检测) 示例6展示了通过onDragSpringLoading接口注册回调,并调用SpringLoadingContext接口获取上下文(当前状态、通知序列)。 ```ts // xxx.ets @Entry @Component struct Index { @State targetText: string = 'Drag Text'; @State state: number = 0; @State currentNotifySequence: number = 0; @State config: DragSpringLoadingConfiguration = { stillTimeLimit: 200, updateInterval: 300, updateNotifyCount: 4, updateToFinishInterval: 300 }; build() { Row() { Column() { Text('start Drag') .fontSize(18) .width('100%') .height(40) .margin(10) .backgroundColor('#008888') Image($r('app.media.startIcon')) .id("ori_image") .width(100) .height(100) .draggable(true) .margin({ left: 15 }) Text('当前状态是: ' + this.state) .fontSize(18) .width('100%') .height(40) .margin(10) Text('当前通知序列是: ' + this.currentNotifySequence) .fontSize(18) .width('100%') .height(40) .margin(10) } .width('45%') .height('100%') Column() { Text('Drag Target Area') .fontSize(20) .width('100%') .height(40) .margin(10) .backgroundColor('#008888') .id("text") Image("") .width(100) .height(100) .draggable(true) .margin({ left: 15 }) .border({ color: Color.Black, width: 2 }) .onDragSpringLoading((context: SpringLoadingContext) => { this.state = context.state; this.currentNotifySequence = context.currentNotifySequence; }, this.config) } .width('45%') .height('100%') .margin({ left: '5%' }) .onDragSpringLoading((context: SpringLoadingContext) => { this.state = context.state; this.currentNotifySequence = context.currentNotifySequence; }, this.config) .id("column") .backgroundColor(Color.Grey) } .height('100%') } } ``` ![DragEvent_getDisplayId](figures/DragSpringLoading.gif) ### 示例7(拖起方延迟提供数据) 示例7展示了在onDragStart中调用setDataLoadParams延迟提供数据接口,并在onDrop中调用startDataLoading异步获取数据接口。 ```ts import { unifiedDataChannel, uniformDataStruct, uniformTypeDescriptor } from '@kit.ArkData'; import { fileUri, fileIo as fs } from '@kit.CoreFileKit'; import { common } from '@kit.AbilityKit'; @Entry @Component struct VideoExample { @State uri: string = ""; @State blockArr: string[] = []; uiContext = this.getUIContext(); udKey: string = ''; build() { Column() { Text('video拖拽') .fontSize('30dp') Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceAround }) { Video({ src: $rawfile('test1.mp4'), controller: new VideoController() }) .width(200) .height(200) .border({ width: 1 }) .draggable(true) .onDragStart((event: DragEvent) => { const context: Context | undefined = this.uiContext.getHostContext(); if (context) { let loadHandler: unifiedDataChannel.DataLoadHandler = (acceptableInfo) => { console.info('acceptableInfo recordCount', acceptableInfo?.recordCount); if (acceptableInfo?.types) { console.info('acceptableInfo types', Array.from(acceptableInfo.types)); } else { console.error('acceptableInfo types is undefined'); } let data = context.resourceManager.getRawFdSync('test1.mp4'); let filePath = context.filesDir + '/test1.mp4'; let file: fs.File = null!; try { file = fs.openSync(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE); let bufferSize = data.length as number; let buf = new ArrayBuffer(bufferSize); fs.readSync(data.fd, buf, { offset: data.offset, length: bufferSize }); fs.writeSync(file.fd, buf, { offset: 0, length: bufferSize }); } catch (error) { console.error(`openSync errorCode: ${error.code}, errorMessage: ${error.message}`); } finally { fs.closeSync(file.fd); } context.resourceManager.closeRawFdSync('test1.mp4') this.uri = fileUri.getUriFromPath(filePath); let videoMp: uniformDataStruct.FileUri = { uniformDataType: 'general.file-uri', oriUri: this.uri, fileType: 'general.video', } let unifiedRecord = new unifiedDataChannel.UnifiedRecord(); let unifiedData = new unifiedDataChannel.UnifiedData(); unifiedRecord.addEntry(uniformTypeDescriptor.UniformDataType.FILE_URI, videoMp); unifiedData.addRecord(unifiedRecord); return unifiedData; } (event as DragEvent).setDataLoadParams({ loadHandler: loadHandler, dataLoadInfo: { types: new Set([uniformTypeDescriptor.UniformDataType.FILE_URI]), recordCount: 1 } }); } }) } .margin({ bottom: 20 }) Row() { Column() { Text('可释放区域') .fontSize('15dp') .height('10%') List() { ForEach(this.blockArr, (item: string, index) => { ListItem() { Video({ src: item, controller: new VideoController() }) .width(100) .height(100) .border({ width: 1 }) } .margin({ left: 30, top: 30 }) }, (item: string) => item) } .border({ width: 1 }) .height('90%') .width('100%') .onDrop((event: DragEvent, extraParams?: string) => { let context = this.uiContext.getHostContext() as common.UIAbilityContext; let pathDir: string = context.distributedFilesDir; let destUri = fileUri.getUriFromPath(pathDir); let progressListener: unifiedDataChannel.DataProgressListener = (progress: unifiedDataChannel.ProgressInfo, dragData: UnifiedData | null) => { if (dragData != null) { let arr: Array = dragData.getRecords(); if (arr.length > 0) { if (arr[0].getType() === uniformTypeDescriptor.UniformDataType.VIDEO) { this.blockArr.splice(JSON.parse(extraParams as string).insertIndex, 0, this.uri); } } else { console.info('dragData arr is null'); } } else { console.info('dragData is undefined'); } console.info(`percentage: ${progress.progress}`); }; let info: unifiedDataChannel.DataLoadInfo = { types: new Set([uniformTypeDescriptor.UniformDataType.VIDEO]), recordCount: 100 } let options: DataSyncOptions = { destUri: destUri, fileConflictOptions: unifiedDataChannel.FileConflictOptions.OVERWRITE, progressIndicator: unifiedDataChannel.ProgressIndicator.DEFAULT, dataProgressListener: progressListener, acceptableInfo: info, } try { this.udKey = (event as DragEvent).startDataLoading(options); console.info('udKey: ', this.udKey); } catch (e) { console.error(`startDataLoading errorCode: ${e.code}, errorMessage: ${e.message}`); } }, { disableDataPrefetch: true }) } .height("50%") .width("90%") .border({ width: 1 }) } Button('取消数据传输') .onClick(() => { try { this.getUIContext().getDragController().cancelDataLoading(this.udKey); } catch (e) { console.error(`cancelDataLoading errorCode: ${e.code}, errorMessage: ${e.message}`); } }) .margin({ top: 10 }) }.width('100%') } } ``` ![DragEvent_setDataLoadParams](figures/dragLoading.gif)