一、拖拽概述
拖拽框架提供了一种通过鼠标或手势触屏的方式传递数据,即从一个组件位置拖出数据,并拖入到另一个组件位置上进行响应,拖出一方提供数据,拖入一方接收和处理数据。该操作可以让用户方便地移动、复制或删除指定内容。
-
拖拽操作:在某个能够响应拖出的组件上长按并滑动触发的拖拽行为,当用户释放时,拖拽操作结束;
-
拖拽背景(背板):用户所拖动数据的形象化表示,开发者可通过onDragStart的CustomerBuilder或DragItemInfo设置,也可以通过dragPreview通用属性设置;
-
拖拽内容:拖动的数据,使用UDMF统一API UnifiedData 进行封装;
-
拖出对象:触发拖拽操作并提供数据的组件;
-
拖入目标:可接收并处理拖动数据的组件;
-
拖拽点:鼠标或手指等与屏幕的接触位置,是否进入组件范围的判定是以接触点是否进入范围进行判断。
一般意义上的组件都可以拖拽,默认可拖拽的组件包括Search、TextInput、TextArea、RichEdiitor、Text、Image、Hyperlink,需判断是否设置了draggable属性为true,其他组件需要额为判断是否设置了onDrageStart回调函数,满足上述条件,可以长按500ms可出发拖拽,长按800ms开始做预览图的浮起动效。
二、组件拖拽
拖拽分为手势拖拽、鼠标拖拽。根据拖拽的数据有Text和File两种数据、
Text的 子类:
PlainText、Hyperlink、HTML
File的子类:Image、Video、Audio
1、文本拖拽
先引入标准化数据通路
import { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData';
给拖拽对象text文本添加上onDragStart属性,设置拖拽的数据。
.onDragStart((event: DragEvent) => { let unifiedData: unifiedDataChannel.UnifiedData | undefined = undefined; this.selectedArr.forEach((value: boolean, index: number) => { if (value) { let text = new unifiedDataChannel.PlainText(); text.textContent = this.arr[index]; if (unifiedData == undefined) { unifiedData = new unifiedDataChannel.UnifiedData(text); } else { unifiedData.addRecord(text); } } }) if (unifiedData != undefined) { //拖拽时的标准数据类型 event.setData(unifiedData); } })
给拖入目标田间allowDrop,可以设置可以拖入其中的数据
.allowDrop([uniformTypeDescriptor.UniformDataType.PLAIN_TEXT])
获取拖拽数据使用onDrop
.onDrop((dragEvent?: DragEvent) => { this.getDataFromUdmf((dragEvent as DragEvent), (event: DragEvent) => { let records: Array<unifiedDataChannel.UnifiedRecord> = event.getData().getRecords(); let plainText: unifiedDataChannel.PlainText = records[0] as unifiedDataChannel.PlainText; this.abstractContent = plainText.abstract as string; this.textContent = plainText.textContent; }) })
综合上述,纯文本拖拽的完整示例为
import { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData'; @Entry @Component struct Index { @State textSource: string = 'drag text' @State targetText: string = '接受文本处'; build() { Row() { Column() { Text('start Drag') .fontSize(18) .width('100%') .height(40) .margin(10) .backgroundColor('#008888') Text(this.textSource) .width('100%') .height(100) .draggable(true) .margin({ left: 15 }) .copyOption(CopyOptions.None) .onDragStart((event) => { let text: unifiedDataChannel.PlainText = new unifiedDataChannel.PlainText(); text.textContent = this.textSource let data: unifiedDataChannel.UnifiedData = new unifiedDataChannel.UnifiedData(text); (event as DragEvent).setData(data); }) }.width('45%') .height('100%') Column() { Text('Drag Target Area') .fontSize(20) .width('100%') .height(40) .margin(10) .backgroundColor('#008888') Text(this.targetText) .width('100%') .height(100) .border({ color: Color.Black, width: 1 }) .margin(15) .allowDrop([uniformTypeDescriptor.UniformDataType.PLAIN_TEXT]) .onDrop((dragEvent?: DragEvent) => { if (dragEvent) { let records: Array<unifiedDataChannel.UnifiedRecord> = dragEvent.getData().getRecords(); let plainText: unifiedDataChannel.PlainText = records[0] as unifiedDataChannel.PlainText; this.targetText = plainText.textContent; } }) }.width('45%') .height('100%') .margin({ left: '5%' }) } .height('100%') } }
此上仅为纯文拖拽,仅仅将一个text组件显示的变量值赋值给另一个变量在另一个text中显示,实际意义微乎其微,下面给出拖拽相应对象的实例。
2、图片拖拽
先引入标准化数据通路和弹窗
import { unifiedDataChannel } from '@kit.ArkData'; import { promptAction } from "@kit.ArkUI"
设置拖拽时的拖拽的信息
.onDragStart((event?: DragEvent) => { if (event) { //创建标准化数据通路中的图片实例 let image = new unifiedDataChannel.Image() //设置传递时的对象信息 image.details = { name: JSON.stringify(item), type: 'image' } //设置好内容放入到标准数据化通路中 let unifiedData = new unifiedDataChannel.UnifiedData(image) //设置收时的标准数据 event.setData(unifiedData) } })
设置拖拽结束后所要进行的删除操作
.onDragEnd((event: DragEvent) => { //图片拖拽成功后删除图片 if (event.getResult() === DragResult.DRAG_SUCCESSFUL) { promptAction.showToast({ duration: 100, message: 'Drag Success' }); this.imageResource.splice(index, 1) this.imageResource = [...this.imageResource] } })
设置接收的数据详情
.onDrop((dragEvent?: DragEvent) => { if (dragEvent) { //获取标准数据中的数据记录 let records: Array<unifiedDataChannel.UnifiedRecord> = dragEvent.getData().getRecords(); let image: unifiedDataChannel.Image = records[0] as unifiedDataChannel.Image; if (image.details) { this.imageResource.push(JSON.parse(image.details['name']) as ImageDataType) } this.imageResource = [...this.imageResource] } })
整合以上代码,完整实例如下
import { unifiedDataChannel } from '@kit.ArkData'; import { promptAction } from "@kit.ArkUI" class ImageDataType { name: string path: string formId: string constructor(name: string = '', path: string = '', formId: string = '') { this.name = name; this.path = path; this.formId = formId; } } @Entry @Component struct DragControllerPage { @State text: ImageDataType = new ImageDataType() @State imageTarget: ImageDataType[] = [] @State imageResource: ImageDataType[] = [ new ImageDataType('1', 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimage109.360doc.com%2FDownloadImg%2F2021%2F10%2F1412%2F232109125_5_20211014120758552&refer=http%3A%2F%2Fimage109.360doc.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1727578734&t=ecd62a60d17b92836a51d796fe0cb731', '1'), new ImageDataType('2', 'https://gips0.baidu.com/it/u=1767063797,2498206723&fm=3039&app=3039&f=JPEG?w=1024&h=1024', '2'), new ImageDataType('3', 'https://img1.baidu.com/it/u=3867150914,864546092&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=811', '3') ] build() { Column() { Row() { ForEach(this.imageResource, (item: ImageDataType, index: number) => { Image(item.path) .width(100) .height(100) .dragPreviewOptions({ numberBadge: 0 })//角标显示 .onDragStart((event?: DragEvent) => { if (event) { //创建标准化数据通路中的图片实例 let image = new unifiedDataChannel.Image() //设置传递时的对象信息 image.details = { name: JSON.stringify(item), type: 'image' } //设置好内容放入到标准数据化通路中 let unifiedData = new unifiedDataChannel.UnifiedData(image) //设置收时的标准数据 event.setData(unifiedData) } }) .onDragEnd((event: DragEvent) => { //图片拖拽成功后删除图片 if (event.getResult() === DragResult.DRAG_SUCCESSFUL) { promptAction.showToast({ duration: 100, message: 'Drag Success' }); this.imageResource.splice(index, 1) this.imageResource = [...this.imageResource] } }) }) } .onDrop((dragEvent?: DragEvent) => { if (dragEvent) { //获取标准数据中的数据记录 let records: Array<unifiedDataChannel.UnifiedRecord> = dragEvent.getData().getRecords(); let image: unifiedDataChannel.Image = records[0] as unifiedDataChannel.Image; if (image.details) { this.imageResource.push(JSON.parse(image.details['name']) as ImageDataType) } this.imageResource = [...this.imageResource] } }) .width('100%').height('50%') Row() { ForEach(this.imageTarget, (item: ImageDataType, index: number) => { Image(item.path) .backgroundColor(Color.Green) .width(100) .height(100) .margin({ top: 20 }) .dragPreviewOptions({ numberBadge: 0 }) .border({ color: Color.Black, width: 1 }) .onDragStart((event?: DragEvent) => { if (event) { //创建标准化数据通路中的图片实例 let image = new unifiedDataChannel.Image() //设置传递时的图片信息 image.details = { name: JSON.stringify(item), type: 'image' } //设置好内容放入到标准数据化通路中 let unifiedData = new unifiedDataChannel.UnifiedData(image) //设置收时的标准数据 event.setData(unifiedData) } }) .onDragEnd((event: DragEvent) => { //图片拖拽成功后删除图片 if (event.getResult() === DragResult.DRAG_SUCCESSFUL) { promptAction.showToast({ duration: 100, message: 'Drag Success' }); this.imageTarget.splice(index, 1) this.imageTarget = [...this.imageTarget] } }) }) }.width('100%').height('50%').backgroundColor(Color.Gray) .onDrop((dragEvent?: DragEvent) => { if (dragEvent) { //获取标准数据中的数据记录 let records: Array<unifiedDataChannel.UnifiedRecord> = dragEvent.getData().getRecords(); let image: unifiedDataChannel.Image = records[0] as unifiedDataChannel.Image; if (image.details) { this.imageTarget.push(JSON.parse(image.details['name']) as ImageDataType) } this.imageTarget = [...this.imageTarget] } }) } .width('100%') .height('100%') } }
三、鸿蒙官方的参考文档
标准化数据通路文档中心
拖拽事件文档中心
拖拽事件指导文档中心
官方拖拽案例DragFramework: 本示例设置组件响应拖拽事件,实现图片、富文本、文本、输入框、列表等组件的拖拽功能。