1# 拖拽事件 2 3拖拽事件指组件被长按后拖拽时触发的事件。 4 5> **说明:** 6> 7> 从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 8> 9> 应用本身预置的资源文件(即应用在安装前的HAP包中已经存在的资源文件)仅支持本地应用内拖拽。 10 11ArkUI框架对以下组件实现了默认的拖拽能力,支持对数据的拖出或拖入响应,开发者只需要将这些组件的[draggale](ts-universal-attributes-drag-drop.md)属性设置为true,即可使用默认拖拽能力。 12 13- 默认支持拖出能力的组件(可从组件上拖出数据):Search、TextInput、TextArea、RichEditor、Text、Image、FormComponent、Hyperlink 14 15- 默认支持拖入能力的组件(目标组件可响应拖入数据):Search、TextInput、TextArea、Video 16 17开发者也可以通过实现通用拖拽事件来自定义拖拽响应。 18 19其他组件需要开发者将draggable属性设置为true,并在onDragStart等接口中实现数据传输相关内容,才能正确处理拖拽。 20 21## 事件 22 23| 名称 | 支持冒泡 | 功能描述 | 24| ------------------------------------------------------------ | -------- | ------------------------------------------------------------ | 25| onDragStart(event: (event?: [DragEvent](#dragevent说明), extraParams?: string) => [CustomBuilder](ts-types.md#custombuilder8) \| [DragItemInfo](#dragiteminfo说明)) | 否 | 第一次拖拽此事件绑定的组件时,长按时间 >= 500ms,然后手指移动距离 >= 10vp,触发回调。<br/>- event:拖拽事件信息,详见[DragEvent](#dragevent说明)。<br/>- extraParams:拖拽事件额外信息,详见[extraParams](#extraparams说明)说明。<br/> 返回值:拖拽过程中显示的组件信息。<br/>触发条件:长按时间 >= 500ms。<br> 事件优先级:长按触发时间 < 500ms,长按事件优先拖拽事件响应,长按触发时间 >= 500ms,拖拽事件优先长按事件响应。 | 26| onDragEnter(event: (event?: [DragEvent](#dragevent说明), extraParams?: string) => void) | 否 | 拖拽进入组件范围内时,触发回调。<br/>- event:拖拽事件信息,包括拖拽点坐标。<br/>- extraParams:拖拽事件额外信息,详见[extraParams](#extraparams说明)说明。<br/>当监听了onDrop事件时,此事件才有效。 | 27| onDragMove(event: (event?: [DragEvent](#dragevent说明), extraParams?: string) => void) | 否 | 拖拽在组件范围内移动时,触发回调。<br/>- event:拖拽事件信息,包括拖拽点坐标。<br/>- extraParams:拖拽事件额外信息,详见[extraParams](#extraparams说明)说明。<br/>当监听了onDrop事件时,此事件才有效。 | 28| onDragLeave(event: (event?: [DragEvent](#dragevent说明), extraParams?: string) => void) | 否 | 拖拽离开组件范围内时,触发回调。<br/>- event:拖拽事件信息,包括拖拽点坐标。<br/>- extraParams:拖拽事件额外信息,详见[extraParams](#extraparams说明)说明。<br/>当监听了onDrop事件时,此事件才有效。 | 29| onDrop(event: (event?: [DragEvent](#dragevent说明), extraParams?: string) => void) | 否 | 绑定此事件的组件可作为拖拽释放目标,当在本组件范围内停止拖拽行为时,触发回调。<br/>- event:拖拽事件信息,包括拖拽点坐标。<br/>- extraParams:拖拽事件额外信息,详见[extraParams](#extraparams说明)说明。 | 30| onDragEnd(event: (event?: [DragEvent](#dragevent说明), extraParams?: string) => void)<sup>10+</sup> | 否 | 绑定此事件的组件触发的拖拽结束后,触发回调。<br/>- event:拖拽事件信息,包括拖拽点坐标。<br/>- extraParams:拖拽事件额外信息,详见[extraParams](#extraparams说明)说明。 | 31 32## DragItemInfo说明 33 34| 名称 | 类型 | 必填 | 描述 | 35| --------- | ---------------------------------------- | ---- | --------------------------------- | 36| pixelMap | [PixelMap](../apis/js-apis-image.md#pixelmap7) | 否 | 设置拖拽过程中显示的图片。 | 37| builder | [CustomBuilder](ts-types.md#custombuilder8) | 否 | 拖拽过程中显示自定义组件,如果设置了pixelMap,则忽略此值。<br/> **说明:** <br/>不支持全局builder。如果builder中使用了[Image](../arkui-ts/ts-basic-components-image.md)组件,应尽量开启同步加载,即配置Image的[syncLoad](../arkui-ts/ts-basic-components-image.md#属性)为true。该builder只用于生成当次拖拽中显示的图片,builder的修改不会同步到当前正在拖拽的图片,对builder的修改需要在下一次拖拽时生效。 | 38| extraInfo | string | 否 | 拖拽项的描述。 | 39 40 41## extraParams说明 42 43 用于返回组件在拖拽中需要用到的额外信息。 44 45 extraParams是Json对象转换的string字符串,可以通过Json.parse转换的Json对象获取如下属性。 46 47| 名称 | 类型 | 描述 | 48| ------------- | ------ | ---------------------------------------- | 49| selectedIndex | number | 当拖拽事件设在父容器的子元素时,selectedIndex表示当前被拖拽子元素是父容器第selectedIndex个子元素,selectedIndex从0开始。<br/>仅在ListItem组件的拖拽事件中生效。 | 50| insertIndex | number | 当前拖拽元素在List组件中放下时,insertIndex表示被拖拽元素插入该组件的第insertIndex个位置,insertIndex从0开始。<br/>仅在List组件的拖拽事件中生效。 | 51 52## DragEvent说明 53 54### 属性 55 56| 名称 | 类型 | 描述 | 57| ------ | ------ | ---------------- | 58| useCustomDropAnimation<sup>10+</sup> | boolean | 当拖拽结束时,是否使能并使用系统默认落位动效。<br/>应用可将该值设定为true来禁用系统默认落位动效,并实现自己的自定义动效。<br/>当不配置或设置为false时,系统默认落位动效生效,此情况下,应用不应再实现自定义动效,以避免动效上的冲突。| 59|dragBehavior<sup>10+</sup> | [DragBehavior](#dragbehavior10) | 切换复制和剪贴模式的角标显示状态。 | 60 61### 方法 62 63| 名称 | 返回值类型 | 描述 | 64| ----------- | ------------------------------- | ------------------------------ | 65| setData(unifiedData: [UnifiedData](../apis/js-apis-data-unifiedDataChannel.md#unifieddata))<sup>10+</sup> | void | 向DragEvent中设置拖拽相关数据。 | 66| getData()<sup>10+</sup> | [UnifiedData](../apis/js-apis-data-unifiedDataChannel.md#unifieddata) | 从DragEvent中获取拖拽相关数据。数据获取结果请参考错误码说明。 | 67| getSummary()<sup>10+</sup> | [Summary](../apis/js-apis-data-unifiedDataChannel.md#summary) | 从DragEvent中获取拖拽相关数据的简介。 | 68| setResult(dragRect: [DragResult](#dragresult10枚举说明))<sup>10+</sup> | void | 向DragEvent中设置拖拽结果。 | 69| getResult()<sup>10+</sup> | [DragResult](#dragresult10枚举说明) | 从DragEvent中获取拖拽结果。 | 70| getPreviewRect()<sup>10+</sup> | [Rectangle](ts-universal-attributes-touch-target.md#rectangle对象说明) | 获取预览图所在的Rectangle。 | 71| getVelocityX()<sup>10+</sup> | number | 获取当前拖拽的x轴方向拖动速度。坐标轴原点为屏幕左上角,单位为vp,分正负方向速度,从左往右为正,反之为负。 | 72| getVelocityY()<sup>10+</sup> | number | 获取当前拖拽的y轴方向拖动速度。坐标轴原点为屏幕左上角,单位为vp,分正负方向速度,从上往下为正,反之为负。 | 73| getVelocity()<sup>10+</sup> | number | 获取当前拖拽的主方向拖动速度。为xy轴方向速度的平方和的算术平方根。 | 74| getWindowX()<sup>10+</sup> | number | 当前拖拽点相对于窗口左上角的x轴坐标,单位为vp。 | 75| getWindowY()<sup>10+</sup> | number | 当前拖拽点相对于窗口左上角的y轴坐标,单位为vp。 | 76| getDisplayX()<sup>10+</sup> | number | 当前拖拽点相对于屏幕左上角的x轴坐标,单位为vp。 | 77| getDisplayY()<sup>10+</sup> | number | 当前拖拽点相对于屏幕左上角的y轴坐标,单位为vp。 | 78| getX()<sup>(deprecated)</sup> | number | 当前拖拽点相对于窗口左上角的x轴坐标,单位为vp。<br>从API verdion 10开始不再维护,建议使用getWindowX()代替。 | 79| getY()<sup>(deprecated)</sup> | number | 当前拖拽点相对于窗口左上角的y轴坐标,单位为vp。<br>从API verdion 10开始不再维护,建议使用getWindowY()代替。 | 80 81 82**错误码:** 83 84以下错误码的详细介绍请参见[drag-event(拖拽事件)](../errorcodes/errorcode-drag-event.md)错误码。 85 86| 错误码ID | 错误信息 | 87| --------- | ------- | 88| 190001 | GetData failed, data not found. | 89| 190002 | GetData failed, data error. | 90 91## DragResult<sup>10+</sup>枚举说明 92 93| 名称 | 描述 | 94| ----- | ----------------- | 95| DRAG_SUCCESSFUL | 拖拽成功 | 96| DRAG_FAILED | 拖拽失败 | 97| DRAG_CANCELED | 拖拽取消 | 98| DROP_ENABLED | 组件允许落入 | 99| DROP_DISABLED | 组件不允许落入 | 100 101## DragBehavior<sup>10+</sup> 102 103需要设置[DragResult](#dragresult10枚举说明)为DROP_ENABLED,并实现[onDrop](#事件)回调时才能够生效。 104 105| 名称 | 描述 | 106| ----- | ----------------- | 107| COPY | 复制模式角标。 | 108| MOVE| 剪贴模式角标。 | 109 110 111## 示例 112 113```ts 114// xxx.ets 115import UDC from '@ohos.data.unifiedDataChannel'; 116import UTD from '@ohos.data.uniformTypeDescriptor'; 117import promptAction from '@ohos.promptAction'; 118import { BusinessError } from '@ohos.base'; 119 120@Entry 121@Component 122struct Index { 123 @State targetImage: string = ''; 124 @State targetText: string = 'Drag Text'; 125 @State imageWidth: number = 100; 126 @State imageHeight: number = 100; 127 @State imgState: Visibility = Visibility.Visible; 128 @State videoSrc: string = 'resource://RAWFILE/02.mp4'; 129 @State abstractContent: string = "abstract"; 130 @State textContent: string = ""; 131 132 getDataFromUdmfRetry(event: DragEvent, callback: (data: DragEvent)=>void) 133 { 134 try { 135 let data:UnifiedData = event.getData(); 136 if (!data) { 137 return false; 138 } 139 let records: Array<UDC.UnifiedRecord> = data.getRecords(); 140 if (!records || records.length <= 0) { 141 return false; 142 } 143 callback(event); 144 return true; 145 } catch (e) { 146 console.log("getData failed, code = " + (e as BusinessError).code + ", message = " + (e as BusinessError).message); 147 return false; 148 } 149 } 150 151 getDataFromUdmf(event: DragEvent, callback: (data: DragEvent) => void) { 152 if (this.getDataFromUdmfRetry(event, callback)) { 153 return; 154 } 155 setTimeout(() => { 156 this.getDataFromUdmfRetry(event, callback); 157 }, 1500); 158 } 159 160 build() { 161 Row() { 162 Column() { 163 Text('start Drag') 164 .fontSize(18) 165 .width('100%') 166 .height(40) 167 .margin(10) 168 .backgroundColor('#008888') 169 Image($r('app.media.icon')) 170 .width(100) 171 .height(100) 172 .draggable(true) 173 .margin({left: 15}) 174 .visibility(this.imgState) 175 .onDragEnd((event)=>{ 176 if (event.getResult() === DragResult.DRAG_SUCCESSFUL) { 177 promptAction.showToast({duration: 100, message: 'Drag Success'}); 178 } else if (event.getResult() === DragResult.DRAG_FAILED) { 179 promptAction.showToast({duration: 100, message: 'Drag failed'}); 180 } 181 }) 182 Text('test drag event') 183 .width('100%') 184 .height(100) 185 .draggable(true) 186 .margin({left: 15}) 187 .copyOption(CopyOptions.InApp) 188 TextArea({placeholder: 'please input words'}) 189 .copyOption(CopyOptions.InApp) 190 .width('100%') 191 .height(50) 192 .draggable(true) 193 Search({placeholder: 'please input you word'}) 194 .searchButton('Search') 195 .width('100%') 196 .height(80) 197 .textFont({size: 20}) 198 Column() { 199 Text('change video source') 200 }.draggable(true) 201 .onDragStart((event)=>{ 202 let video: UDC.Video = new UDC.Video(); 203 video.videoUri = '/resources/rawfile/01.mp4'; 204 let data: UDC.UnifiedData = new UDC.UnifiedData(video); 205 (event as DragEvent).setData(data); 206 }) 207 Column() { 208 Text('this is abstract') 209 .fontSize(20) 210 .width('100%') 211 }.margin({left: 40, top: 20}) 212 .width('100%') 213 .height(100) 214 .onDragStart((event)=>{ 215 let data: UDC.PlainText = new UDC.PlainText(); 216 data.abstract = 'this is abstract'; 217 data.textContent = 'this is content this is content'; 218 (event as DragEvent).setData(new UDC.UnifiedData(data)); 219 }) 220 }.width('45%') 221 .height('100%') 222 223 Column() { 224 Text('Drag Target Area') 225 .fontSize(20) 226 .width('100%') 227 .height(40) 228 .margin(10) 229 .backgroundColor('#008888') 230 Image(this.targetImage) 231 .width(this.imageWidth) 232 .height(this.imageHeight) 233 .draggable(true) 234 .margin({ left: 15 }) 235 .border({ color: Color.Black, width: 1 }) 236 .allowDrop([UTD.UniformDataType.IMAGE]) 237 .onDrop((dragEvent?: DragEvent) => { 238 this.getDataFromUdmf((dragEvent as DragEvent), (event: DragEvent) => { 239 let records: Array<UDC.UnifiedRecord> = event.getData().getRecords(); 240 let rect: Rectangle = event.getPreviewRect(); 241 this.imageWidth = Number(rect.width); 242 this.imageHeight = Number(rect.height); 243 this.targetImage = (records[0] as UDC.Image).imageUri; 244 event.useCustomDropAnimation = false; 245 animateTo({ duration: 1000 }, () => { 246 this.imageWidth = 100; 247 this.imageHeight = 100; 248 this.imgState = Visibility.None; 249 }) 250 event.setResult(DragResult.DRAG_SUCCESSFUL); 251 }) 252 }) 253 254 Text(this.targetText) 255 .width('100%') 256 .height(100) 257 .border({ color: Color.Black, width: 1 }) 258 .margin(15) 259 .allowDrop([UTD.UniformDataType.TEXT]) 260 .onDrop((dragEvent?: DragEvent) => { 261 this.getDataFromUdmf((dragEvent as DragEvent), (event: DragEvent) => { 262 let records: Array<UDC.UnifiedRecord> = event.getData().getRecords(); 263 let plainText: UDC.PlainText = records[0] as UDC.PlainText; 264 this.targetText = plainText.textContent; 265 }) 266 }) 267 268 Video({ src: this.videoSrc, previewUri: $r('app.media.icon') }) 269 .width('100%') 270 .height(200) 271 .controls(true) 272 .allowDrop([UTD.UniformDataType.VIDEO]) 273 274 Column() { 275 Text(this.abstractContent).fontSize(20).width('100%') 276 Text(this.textContent).fontSize(15).width('100%') 277 } 278 .width('100%') 279 .height(100) 280 .margin(20) 281 .border({ color: Color.Black, width: 1 }) 282 .allowDrop([UTD.UniformDataType.PLAIN_TEXT]) 283 .onDrop((dragEvent?: DragEvent) => { 284 this.getDataFromUdmf((dragEvent as DragEvent), (event: DragEvent) => { 285 let records: Array<UDC.UnifiedRecord> = event.getData().getRecords(); 286 let plainText: UDC.PlainText = records[0] as UDC.PlainText; 287 this.abstractContent = plainText.abstract as string; 288 this.textContent = plainText.textContent; 289 }) 290 }) 291 }.width('45%') 292 .height('100%') 293 .margin({ left: '5%' }) 294 } 295 .height('100%') 296 } 297} 298``` 299