拖拽事件指组件被长按后拖拽时触发的事件。
说明:
从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
应用本身预置的资源文件(即应用在安装前的HAP包中已经存在的资源文件)仅支持本地应用内拖拽。
ArkUI框架对以下组件实现了默认的拖拽能力,支持对数据的拖出或拖入响应,开发者只需要将这些组件的draggable属性设置为true,即可使用默认拖拽能力。
默认支持拖出能力的组件(可从组件上拖出数据):Search、TextInput、TextArea、RichEditor、Text、Image、FormComponent、Hyperlink
默认支持拖入能力的组件(目标组件可响应拖入数据):Search、TextInput、TextArea、Video
开发者也可以通过实现通用拖拽事件来自定义拖拽响应。
其他组件需要开发者将draggable属性设置为true,并在onDragStart等接口中实现数据传输相关内容,才能正确处理拖拽。
onDragStart(event: (event: DragEvent, extraParams?: string) => CustomBuilder | DragItemInfo)
第一次拖拽此事件绑定的组件时,长按时间 >= 500ms,然后手指移动距离 >= 10vp,触发回调。
事件优先级: 长按触发时间 < 500ms,长按事件优先拖拽事件响应,长按触发时间 >= 500ms,拖拽事件优先长按事件响应。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| event | DragEvent | 是 | 拖拽事件信息。 |
| extraParams | extraParams | 否 | 拖拽事件额外信息。 |
返回值:
| 类型 | 说明 |
|---|---|
| CustomBuilder | DragItemInfo | 拽过程中显示的组件信息。 说明: 不支持全局builder。 |
onDragEnter(event: (event: DragEvent, extraParams?: string) => void)
拖拽进入组件范围内时,触发回调,当监听了onDrop事件时,此事件才有效。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| event | DragEvent | 是 | 拖拽事件信息,包括拖拽点坐标。 |
| extraParams | extraParams | 否 | 拖拽事件额外信息。 |
onDragMove(event: (event: DragEvent, extraParams?: string) => void)
拖拽在组件范围内移动时,触发回调,当监听了onDrop事件时,此事件才有效。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| event | DragEvent | 是 | 拖拽事件信息,包括拖拽点坐标。 |
| extraParams | extraParams | 否 | 拖拽事件额外信息。 |
onDragLeave(event: (event: DragEvent, extraParams?: string) => void)
拖拽离开组件范围内时,触发回调,当监听了onDrop事件时,此事件才有效。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| event | DragEvent | 是 | 拖拽事件信息,包括拖拽点坐标。 |
| extraParams | extraParams | 否 | 拖拽事件额外信息。 |
onDrop(event: (event: DragEvent, extraParams?: string) => void)
绑定此事件的组件可作为拖拽释放目标,当在本组件范围内停止拖拽行为时,触发回调。如果没有显式使用event.setResult(),则默认result为DRAG_SUCCESSFUL。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| event | DragEvent | 是 | 拖拽事件信息,包括拖拽点坐标。 |
| extraParams | extraParams | 否 | 拖拽事件额外信息。 |
onDragEnd(event: (event: DragEvent, extraParams?: string) => void)
绑定此事件的组件触发的拖拽结束后,触发回调。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| event | DragEvent | 是 | 拖拽事件信息,包括拖拽点坐标。 |
| extraParams | extraParams | 否 | 拖拽事件额外信息。 |
| 名称 | 类型 | 必填 | 描述 |
|---|---|---|---|
| pixelMap | PixelMap | 否 | 设置拖拽过程中显示的图片。 |
| builder | CustomBuilder | 否 | 拖拽过程中显示自定义组件,如果设置了pixelMap,则忽略此值。 说明: 不支持全局Builder定义。如果builder中使用了Image组件,应尽量开启同步加载,即配置Image的syncLoad为true。 |
| extraInfo | string | 否 | 拖拽项的描述。 |
用于返回组件在拖拽中需要用到的额外信息。
extraParams是Json对象转换的string字符串,可以通过Json.parse转换的Json对象获取如下属性。
| 名称 | 类型 | 描述 |
|---|---|---|
| selectedIndex | number | 当拖拽事件设在父容器的子元素时,selectedIndex表示当前被拖拽子元素是父容器第selectedIndex个子元素,selectedIndex从0开始。 仅在ListItem组件的拖拽事件中生效。 |
| insertIndex | number | 当前拖拽元素在List组件中放下时,insertIndex表示被拖拽元素插入该组件的第insertIndex个位置,insertIndex从0开始。 仅在List组件的拖拽事件中生效。 |
| 名称 | 类型 | 描述 |
|---|---|---|
| useCustomDropAnimation10+ | boolean | 当拖拽结束时,是否使能并使用系统默认落位动效。 应用可将该值设定为true来禁用系统默认落位动效,并实现自己的自定义动效。 当不配置或设置为false时,系统默认落位动效生效,此情况下,应用不应再实现自定义动效,以避免动效上的冲突。 |
| dragBehavior10+ | DragBehavior | 切换复制和剪贴模式的角标显示状态。 |
| 名称 | 返回值类型 | 描述 |
|---|---|---|
| setData(unifiedData: UnifiedData)10+ | void | 向DragEvent中设置拖拽相关数据。 |
| getData()10+ | UnifiedData | 从DragEvent中获取拖拽相关数据。数据获取结果请参考错误码说明。 |
| getSummary()10+ | Summary | 从DragEvent中获取拖拽相关数据的简介。 |
| setResult(dragRect: DragResult)10+ | void | 向DragEvent中设置拖拽结果。 |
| getResult()10+ | DragResult | 从DragEvent中获取拖拽结果。 |
| getPreviewRect()10+ | Rectangle | 获取预览图所在的Rectangle。 |
| getVelocityX()10+ | number | 获取当前拖拽的x轴方向拖动速度。坐标轴原点为屏幕左上角,单位为vp,分正负方向速度,从左往右为正,反之为负。 |
| getVelocityY()10+ | number | 获取当前拖拽的y轴方向拖动速度。坐标轴原点为屏幕左上角,单位为vp,分正负方向速度,从上往下为正,反之为负。 |
| getVelocity()10+ | number | 获取当前拖拽的主方向拖动速度。为xy轴方向速度的平方和的算术平方根。 |
| getWindowX()10+ | number | 当前拖拽点相对于窗口左上角的x轴坐标,单位为vp。 |
| getWindowY()10+ | number | 当前拖拽点相对于窗口左上角的y轴坐标,单位为vp。 |
| getDisplayX()10+ | number | 当前拖拽点相对于屏幕左上角的x轴坐标,单位为vp。 |
| getDisplayY()10+ | number | 当前拖拽点相对于屏幕左上角的y轴坐标,单位为vp。 |
| getX()(deprecated) | number | 当前拖拽点相对于窗口左上角的x轴坐标,单位为vp。 从API verdion 10开始不再维护,建议使用getWindowX()代替。 |
| getY()(deprecated) | number | 当前拖拽点相对于窗口左上角的y轴坐标,单位为vp。 从API verdion 10开始不再维护,建议使用getWindowY()代替。 |
错误码:
以下错误码的详细介绍请参见drag-event(拖拽事件)错误码。
| 错误码ID | 错误信息 |
|---|---|
| 190001 | GetData failed, data not found. |
| 190002 | GetData failed, data error. |
| 名称 | 描述 |
|---|---|
| DRAG_SUCCESSFUL | 拖拽成功,在onDrop中使用。 |
| DRAG_FAILED | 拖拽失败,在onDrop中使用。 |
| DRAG_CANCELED | 拖拽取消,在onDrop中使用。 |
| DROP_ENABLED | 组件允许落入,在onDragMove中使用。 |
| DROP_DISABLED | 组件不允许落入,在onDragMove中使用。 |
需要设置DragResult为DROP_ENABLED,并实现onDrop回调时才能够生效。
| 名称 | 描述 |
|---|---|
| COPY | 复制模式角标。 |
| MOVE | 剪贴模式角标。 |
- // xxx.ets
- import UDC from '@ohos.data.unifiedDataChannel';
- import UTD from '@ohos.data.uniformTypeDescriptor';
- import promptAction from '@ohos.promptAction';
- import { BusinessError } from '@ohos.base';
-
- @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 videoSrc: string = 'resource://RAWFILE/02.mp4';
- @State abstractContent: string = "abstract";
- @State textContent: string = "";
-
- @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<UDC.UnifiedRecord> = 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);
- }
-
- 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('change video source')
- }.draggable(true)
- .onDragStart((event) => {
- let video: UDC.Video = new UDC.Video();
- video.videoUri = '/resources/rawfile/01.mp4';
- let data: UDC.UnifiedData = new UDC.UnifiedData(video);
- (event as DragEvent).setData(data);
- return { builder: () => {
- this.pixelMapBuilder()
- }, extraInfo: 'extra info' };
- })
-
- Column() {
- Text('this is abstract')
- .fontSize(20)
- .width('100%')
- }.margin({ left: 40, top: 20 })
- .width('100%')
- .height(100)
- .onDragStart((event) => {
- let data: UDC.PlainText = new UDC.PlainText();
- data.abstract = 'this is abstract';
- data.textContent = 'this is content this is content';
- (event as DragEvent).setData(new UDC.UnifiedData(data));
- })
- }.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([UTD.UniformDataType.IMAGE])
- .onDrop((dragEvent?: DragEvent) => {
- this.getDataFromUdmf((dragEvent as DragEvent), (event: DragEvent) => {
- let records: Array<UDC.UnifiedRecord> = event.getData().getRecords();
- let rect: Rectangle = event.getPreviewRect();
- this.imageWidth = Number(rect.width);
- this.imageHeight = Number(rect.height);
- this.targetImage = (records[0] as UDC.Image).imageUri;
- event.useCustomDropAnimation = false;
- animateTo({ duration: 1000 }, () => {
- this.imageWidth = 100;
- this.imageHeight = 100;
- 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([UTD.UniformDataType.TEXT])
- .onDrop((dragEvent?: DragEvent) => {
- this.getDataFromUdmf((dragEvent as DragEvent), (event: DragEvent) => {
- let records: Array<UDC.UnifiedRecord> = event.getData().getRecords();
- let plainText: UDC.PlainText = records[0] as UDC.PlainText;
- this.targetText = plainText.textContent;
- })
- })
-
- Video({ src: this.videoSrc, previewUri: $r('app.media.icon') })
- .width('100%')
- .height(200)
- .controls(true)
- .allowDrop([UTD.UniformDataType.VIDEO])
-
- 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([UTD.UniformDataType.PLAIN_TEXT])
- .onDrop((dragEvent?: DragEvent) => {
- this.getDataFromUdmf((dragEvent as DragEvent), (event: DragEvent) => {
- let records: Array<UDC.UnifiedRecord> = event.getData().getRecords();
- let plainText: UDC.PlainText = records[0] as UDC.PlainText;
- this.abstractContent = plainText.abstract as string;
- this.textContent = plainText.textContent;
- })
- })
- }.width('45%')
- .height('100%')
- .margin({ left: '5%' })
- }
- .height('100%')
- }
- }
最后,有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(Harmony NEXT)资料用来跟着学习是非常有必要的。
这份鸿蒙(Harmony NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点。
希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!
获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

HarmonOS基础技能







有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。
获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料


OpenHarmony北向、南向开发环境搭建




获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料
总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。
