鸿蒙HarmonyOS NEXT - 拖拽

一、拖拽概述

拖拽框架提供了一种通过鼠标或手势触屏的方式传递数据,即从一个组件位置拖出数据,并拖入到另一个组件位置上进行响应,拖出一方提供数据,拖入一方接收和处理数据。该操作可以让用户方便地移动、复制或删除指定内容。

  • 拖拽操作:在某个能够响应拖出的组件上长按并滑动触发的拖拽行为,当用户释放时,拖拽操作结束;

  • 拖拽背景(背板):用户所拖动数据的形象化表示,开发者可通过onDragStartCustomerBuilderDragItemInfo设置,也可以通过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: 本示例设置组件响应拖拽事件,实现图片、富文本、文本、输入框、列表等组件的拖拽功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值