鸿蒙Harmony应用开发—ArkTS声明式开发(拖拽事件)

拖拽事件指组件被长按后拖拽时触发的事件。

说明:

从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。

应用本身预置的资源文件(即应用在安装前的HAP包中已经存在的资源文件)仅支持本地应用内拖拽。

ArkUI框架对以下组件实现了默认的拖拽能力,支持对数据的拖出或拖入响应,开发者只需要将这些组件的draggable属性设置为true,即可使用默认拖拽能力。

  • 默认支持拖出能力的组件(可从组件上拖出数据):Search、TextInput、TextArea、RichEditor、Text、Image、FormComponent、Hyperlink

  • 默认支持拖入能力的组件(目标组件可响应拖入数据):Search、TextInput、TextArea、Video

开发者也可以通过实现通用拖拽事件来自定义拖拽响应。

其他组件需要开发者将draggable属性设置为true,并在onDragStart等接口中实现数据传输相关内容,才能正确处理拖拽。

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

onDragEnter(event: (event: DragEvent, extraParams?: string) => void)

拖拽进入组件范围内时,触发回调,当监听了onDrop事件时,此事件才有效。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 类型 必填 说明
event DragEvent 拖拽事件信息,包括拖拽点坐标。
extraParams extraParams 拖拽事件额外信息。

onDragMove

onDragMove(event: (event: DragEvent, extraParams?: string) => void)

拖拽在组件范围内移动时,触发回调,当监听了onDrop事件时,此事件才有效。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 类型 必填 说明
event DragEvent 拖拽事件信息,包括拖拽点坐标。
extraParams extraParams 拖拽事件额外信息。

onDragLeave

onDragLeave(event: (event: DragEvent, extraParams?: string) => void)

拖拽离开组件范围内时,触发回调,当监听了onDrop事件时,此事件才有效。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 类型 必填 说明
event DragEvent 拖拽事件信息,包括拖拽点坐标。
extraParams extraParams 拖拽事件额外信息。

onDrop

onDrop(event: (event: DragEvent, extraParams?: string) => void)

绑定此事件的组件可作为拖拽释放目标,当在本组件范围内停止拖拽行为时,触发回调。如果没有显式使用event.setResult(),则默认result为DRAG_SUCCESSFUL。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 类型 必填 说明
event DragEvent 拖拽事件信息,包括拖拽点坐标。
extraParams extraParams 拖拽事件额外信息。

onDragEnd

onDragEnd(event: (event: DragEvent, extraParams?: string) => void)

绑定此事件的组件触发的拖拽结束后,触发回调。

系统能力: SystemCapability.ArkUI.ArkUI.Full

参数:

参数名 类型 必填 说明
event DragEvent 拖拽事件信息,包括拖拽点坐标。
extraParams extraParams 拖拽事件额外信息。

DragItemInfo说明

名称 类型 必填 描述
pixelMap PixelMap 设置拖拽过程中显示的图片。
builder CustomBuilder 拖拽过程中显示自定义组件,如果设置了pixelMap,则忽略此值。 说明: 不支持全局Builder定义。如果builder中使用了Image组件,应尽量开启同步加载,即配置Image的syncLoad为true。
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说明

属性

名称 类型 描述
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.

DragResult10+枚举说明

名称 描述
DRAG_SUCCESSFUL 拖拽成功,在onDrop中使用。
DRAG_FAILED 拖拽失败,在onDrop中使用。
DRAG_CANCELED 拖拽取消,在onDrop中使用。
DROP_ENABLED 组件允许落入,在onDragMove中使用。
DROP_DISABLED 组件不允许落入,在onDragMove中使用。

DragBehavior10+

需要设置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学习资料****

鸿蒙(Harmony NEXT)最新学习路线

  • HarmonOS基础技能
  • HarmonOS就业必备技能
  • HarmonOS多媒体技术
  • 鸿蒙NaPi组件进阶
  • HarmonOS高级技能
  • 初识HarmonOS内核
  • 实战就业级设备开发

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

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料****

《鸿蒙 (OpenHarmony)开发入门教学视频》

《鸿蒙生态应用开发V2.0白皮书》

《鸿蒙 (OpenHarmony)开发基础到实战手册》

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

《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .......

《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ......

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ......

获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料****

总结

总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。

相关推荐
雨白8 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
幽蓝计划10 小时前
HarmonyOS NEXT仓颉开发语言实战案例:动态广场
华为·harmonyos
kk爱闹10 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空11 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭12 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日13 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安13 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑13 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
万少16 小时前
第五款 HarmonyOS 上架作品 奇趣故事匣 来了
前端·harmonyos·客户端
幽蓝计划16 小时前
HarmonyOS NEXT仓颉开发语言实战案例:电影App
华为·harmonyos