1# 拖拽控制 2 3设置组件是否可以响应拖拽事件。 4 5> **说明:** 6> 7> 从API Version 10开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 8 9ArkUI框架对以下组件实现了默认的拖拽能力,支持对数据的拖出或拖入响应。开发者也可以通过实现通用拖拽事件来自定义拖拽响应。 10 11- 默认支持拖出能力的组件(可从组件上拖出数据):[Search](ts-basic-components-search.md)、[TextInput](ts-basic-components-textinput.md)、[TextArea](ts-basic-components-textarea.md)、[RichEditor](ts-basic-components-richeditor.md)、[Text](ts-basic-components-text.md)、[Image](ts-basic-components-image.md)、<!--Del-->[FormComponent](ts-basic-components-formcomponent-sys.md)、<!--DelEnd-->[Hyperlink](ts-container-hyperlink.md),开发者可通过设置这些组件的[draggable](ts-universal-attributes-drag-drop.md#draggable)属性来控制对默认拖拽能力的使用。 12 13- 默认支持拖入能力的组件(目标组件可响应拖入数据):[Search](ts-basic-components-search.md)、[TextInput](ts-basic-components-textinput.md)、[TextArea](ts-basic-components-textarea.md)、[RichEditor](ts-basic-components-richeditor.md),开发者可通过设置这些组件的[allowDrop](ts-universal-attributes-drag-drop.md#allowdrop)属性为null来禁用对默认拖入能力的支持。 14 15<!--RP1--><!--RP1End-->其他组件需要开发者将draggable属性设置为true,并在onDragStart等接口中实现数据传输相关内容,才能正确处理拖拽。 16 17> **说明:** 18> 19> Text组件需配合[copyOption](ts-basic-components-text.md#copyoption9)一起使用,设置copyOptions为CopyOptions.InApp或者CopyOptions.LocalDevice。 20 21## allowDrop 22 23allowDrop(value: Array<UniformDataType> | null) 24 25设置该组件上允许落入的数据类型。 26 27**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 28 29**系统能力:** SystemCapability.ArkUI.ArkUI.Full 30 31**参数:** 32 33| 参数名 | 类型 | 必填 | 说明 | 34| ------ | ------------------------------------------------------------ | ---- | ----------------------------------------------- | 35| value | Array\<[UniformDataType](../../apis-arkdata/js-apis-data-uniformTypeDescriptor.md#uniformdatatype)> \| null<sup>12+</sup> | 是 | 设置该组件上允许落入的数据类型。从API version 12开始,允许设置成null使该组件不接受所有的数据类型。<br/>默认值:空 | 36 37## draggable 38 39draggable(value: boolean) 40 41设置该组件是否允许进行拖拽。 42 43**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 44 45**系统能力:** SystemCapability.ArkUI.ArkUI.Full 46 47**参数:** 48 49| 参数名 | 类型 | 必填 | 说明 | 50| ------ | ------- | ---- | ---------------------------------------------- | 51| value | boolean | 是 | 设置该组件是否允许进行拖拽。true表示允许拖拽,false表示不允许拖拽。<br/>默认值:false | 52 53## dragPreview<sup>11+</sup> 54 55dragPreview(value: CustomBuilder | DragItemInfo | string) 56 57设置组件拖拽过程中的预览图。 58 59**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 60 61**系统能力:** SystemCapability.ArkUI.ArkUI.Full 62 63**参数:** 64 65| 参数名 | 类型 | 必填 | 说明 | 66| ------ | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ | 67| value | [CustomBuilder](ts-types.md#custombuilder8) \| [DragItemInfo](ts-universal-events-drag-drop.md#dragiteminfo说明) \| string<sup>12+</sup> | 是 | 设置组件拖拽过程中的预览图,仅在onDragStart拖拽方式中有效。<br/>当组件支持拖拽并同时设置[bindContextMenu](ts-universal-attributes-menu.md#bindcontextmenu8)的预览图时,则长按浮起的预览图以[bindContextMenu](ts-universal-attributes-menu.md#bindcontextmenu8)设置的预览图为准。开发者在[onDragStart](ts-universal-events-drag-drop.md#onDragStart)中返回的背板图优先级低于[dragPreview](ts-universal-attributes-drag-drop.md#dragPreview11)设置的预览图,当设置了[dragPreview](ts-universal-attributes-drag-drop.md#dragPreview11)预览图时,拖拽过程中的背板图使用[dragPreview](ts-universal-attributes-drag-drop.md#dragPreview11)预览图。由于[CustomBuilder](ts-types.md#custombuilder8)需要离线渲染之后才能使用,因此存在一定的性能开销和时延,推荐优先使用 [DragItemInfo](ts-universal-events-drag-drop.md#dragiteminfo说明)中的[PixelMap](../../apis-image-kit/js-apis-image.md#pixelmap7)方式。<br/> 当传入类型为string的id时,则将id对应组件的截图作为预览图。如果id对应的组件无法查找到,或者id对应的组件Visibility属性设置成none/hidden,则对组件自身进行截图作为拖拽预览图。目前截图不含有亮度、阴影、模糊和旋转等视觉效果。<br/>默认值:空<br/> | 68 69## dragPreview<sup>15+</sup> 70 71dragPreview(preview: CustomBuilder | DragItemInfo | string, config?: PreviewConfiguration):T 72 73自定义组件拖拽过程中的预览图,仅用于设置浮起效果或者禁用浮起效果。 74 75**原子化服务API:** 从API version 15开始,该接口支持在原子化服务中使用。 76 77**系统能力:** SystemCapability.ArkUI.ArkUI.Full 78 79**参数:** 80 81| 参数名 | 类型 | 必填 | 说明 | 82| ------ | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ | 83| preview | [CustomBuilder](ts-types.md#custombuilder8) \| [DragItemInfo](ts-universal-events-drag-drop.md#dragiteminfo说明) \| string | 是 | 设置组件拖拽过程中的预览图,仅在onDragStart拖拽方式中有效。<br/>当组件支持拖拽并同时设置[bindContextMenu](ts-universal-attributes-menu.md#bindcontextmenu8)的预览图时,则长按浮起的预览图以[bindContextMenu](ts-universal-attributes-menu.md#bindcontextmenu8)设置的预览图为准。开发者在[onDragStart](ts-universal-events-drag-drop.md#ondragstart)中返回的背板图优先级低于[dragPreview](ts-universal-attributes-drag-drop.md#dragpreview11)设置的预览图,当设置了[dragPreview](ts-universal-attributes-drag-drop.md#dragpreview11)预览图时,拖拽过程中的背板图使用[dragPreview](ts-universal-attributes-drag-drop.md#dragpreview11)预览图。由于[CustomBuilder](ts-types.md#custombuilder8)需要离线渲染之后才能使用,因此存在一定的性能开销和时延,推荐优先使用 [DragItemInfo](ts-universal-events-drag-drop.md#dragiteminfo说明)中的[PixelMap](../../apis-image-kit/js-apis-image.md#pixelmap7)方式。<br/> 当传入类型为string的id时,则将id对应组件的截图作为预览图。如果id对应的组件无法查找到,或者id对应的组件Visibility属性设置成none/hidden,则对组件自身进行截图作为拖拽预览图。目前截图不含有亮度、阴影、模糊和旋转等视觉效果。<br/>默认值:空 | 84| config | [PreviewConfiguration](ts-universal-events-drag-drop.md#previewconfiguration15) | 是 | 对自定义拖拽过程中的预览图进行配置。<br/>只对[dragPreview](#dragpreview11)中的预览生效。<br/>默认值:空 | 85 86## dragPreviewOptions<sup>11+</sup> 87 88dragPreviewOptions(value: DragPreviewOptions, options?: DragInteractionOptions) 89 90设置拖拽过程中背板图处理模式及数量角标的显示。不支持onItemDragStart拖拽方式。 91 92**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 93 94**系统能力:** SystemCapability.ArkUI.ArkUI.Full 95 96**参数:** 97 98| 参数名 | 类型 | 必填 | 说明 | 99| ------ | -------------------------------------------------------------- | ---- | ------------------------------------------------------------ | 100| value | [DragPreviewOptions](#dragpreviewoptions11)<sup>11+</sup> | 是 | 设置拖拽过程中背板图处理模式及数量角标的显示。<br/>默认值:空 | 101| options<sup>12+</sup>| [DragInteractionOptions](#draginteractionoptions12)<sup>12+</sup>| 否 | 设置拖拽过程中背板图浮起的交互模式。<br/>默认值:空| 102 103## DragPreviewOptions<sup>11+</sup> 104 105**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 106 107| 名称 | 类型 | 必填 | 描述 | 108| -------- | -------- | -------- | -------- | 109| mode | [DragPreviewMode](#dragpreviewmode11枚举说明) \| Array<[DragPreviewMode](#dragpreviewmode11枚举说明)><sup>12+</sup> | 否 | 表示拖拽过程中背板图处理模式。<br/>默认值:DragPreviewMode.AUTO<br/>当组件同时设置DragPreviewMode.AUTO和其它枚举值时,以DragPreviewMode.AUTO为准,其它枚举值设置无效。| 110| numberBadge<sup>12+</sup> | boolean \| number | 否 | 控制数量角标是否显示,或强制设置显示的数量。当设置数量角标时取值范围为[0,2<sup>31</sup>-1],超过取值范围时会按默认状态处理。当设置为浮点数时,只显示整数部分。<br/>**说明:** <br>在多选拖拽场景,需通过该接口设置拖拽对象的数量。<br/>默认值:true | 111| modifier<sup>12+</sup> | [ImageModifier](ts-universal-attributes-attribute-modifier.md)| 否 | 用于配置拖拽背板图的样式Modifier对象,可使用图片组件所支持的属性和样式来配置背板图样式(参考示例6),当前支持透明度,阴影,背景模糊度,圆角。文本拖拽只支持默认效果,不支持通过modifier进行自定义。<br/>1.透明度<br/>通过[opacity](ts-universal-attributes-opacity.md#opacity)设置透明度,不透明度的取值范围为0-1。设置0或不设置时采用默认值0.95,设置1或异常值时不透明。<br/>2.阴影<br/>通过[shadow](ts-universal-attributes-image-effect.md#shadow)设置阴影。<br/>3.背景模糊度<br/>通过[backgroundEffect](ts-universal-attributes-background.md#backgroundeffect11)或[backgroundBlurStyle](ts-universal-attributes-background.md#backgroundblurstyle)设置背景模糊度,如果两者同时设置,以backgroundEffect为准。<br/>4.圆角<br/>通过[border](ts-universal-attributes-border.md#border)或[borderRadius](ts-universal-attributes-border.md#borderRadius)设置圆角,当同时在mode和modifier中设置圆角,mode设置的圆角显示优先级低于modifier设置。<br/>默认值:空,无法修改属性| 112 113## DragPreviewMode<sup>11+</sup>枚举说明 114 115**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 116 117| 名称 | 枚举值 | 描述 | 118| -------- | ------- | -------- | 119| AUTO | 1 | 系统根据拖拽场景自动改变跟手点位置,根据规则自动对拖拽背板图进行缩放变换等。 | 120| DISABLE_SCALE | 2 | 禁用系统对拖拽背板图的缩放行为。 | 121| ENABLE_DEFAULT_SHADOW<sup>12+</sup> | 3 | 启用非文本类组件默认阴影效果。 | 122| ENABLE_DEFAULT_RADIUS<sup>12+</sup> | 4 | 启用非文本类组件统一圆角效果,默认值12vp。当应用自身设置的圆角值大于默认值或modifier设置的圆角时,则显示应用自定义圆角效果。 | 123 124## DragInteractionOptions<sup>12+</sup> 125 126**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 127 128| 名称 | 类型 | 必填 | 描述 | 129| -------- | -------- | -------- | -------- | 130| isMultiSelectionEnabled | boolean | 否 | 表示拖拽过程中背板图是否支持多选聚拢效果。true表示支持多选聚拢效果,false表示不支持多选聚拢效果。该参数只在[Grid](ts-container-grid.md)和[List](ts-container-list.md)组件中的[GridItem](ts-container-griditem.md)组件和[ListItem](ts-container-listitem.md)组件生效。<br/>当一个item组件设置为多选拖拽时,该组件的子组件不可拖拽。聚拢组件预览图设置的优先级为[dragPreview](#dragpreview11)中的string,dragPreview中的PixelMap,组件自截图,不支持dragPreview中的Builder形式。<br/>不支持组件绑定[bindContextMenu](ts-universal-attributes-menu.md#bindcontextmenu12)中参数存在isShown的模式。<br/>默认值:false<br/> | 131| defaultAnimationBeforeLifting | boolean | 否 | 表示是否启用长按浮起阶段组件自身的默认点按效果(缩小)。true表示启用默认点按效果,false表示不启用默认点按效果。<br/>默认值:false <br/> | 132| isLiftingDisabled<sup>15+</sup> | boolean | 否 | 表示长按拖拽时,是否禁用浮起效果。true表示禁用浮起效果,false表示不禁用浮起效果。<br/>如果设置为true,当组件支持拖拽并同时设置[bindContextMenu](ts-universal-attributes-menu.md#bindcontextmenu8)时,仅弹出配置的自定义菜单预览。 <br/>默认值:false | 133 134## 示例 135### 示例1(允许拖拽和落入) 136 137该示例通过配置allowDrop和draggable分别设置组件是否可落入和拖拽。 138 139```ts 140// xxx.ets 141import { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData'; 142 143@Entry 144@Component 145struct ImageExample { 146 @State uri: string = "" 147 @State AblockArr: string[] = [] 148 @State BblockArr: string[] = [] 149 @State AVisible: Visibility = Visibility.Visible 150 @State dragSuccess :Boolean = false 151 152 build() { 153 Column() { 154 Text('Image拖拽') 155 .fontSize('30dp') 156 Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceAround }) { 157 Image($r('app.media.icon')) 158 .width(100) 159 .height(100) 160 .border({ width: 1 }) 161 .visibility(this.AVisible) 162 .draggable(true) 163 .onDragEnd((event: DragEvent) => { 164 let ret = event.getResult(); 165 if(ret == 0) { 166 console.log("enter ret == 0") 167 this.AVisible = Visibility.Hidden; 168 } else { 169 console.log("enter ret != 0") 170 this.AVisible = Visibility.Visible; 171 } 172 }) 173 } 174 .margin({ bottom: 20 }) 175 Row() { 176 Column(){ 177 Text('不允许释放区域') 178 .fontSize('15dp') 179 .height('10%') 180 List(){ 181 ForEach(this.AblockArr, (item:string, index) => { 182 ListItem() { 183 Image(item) 184 .width(100) 185 .height(100) 186 .border({width: 1}) 187 } 188 .margin({ left: 30 , top : 30}) 189 }, (item:string) => item) 190 } 191 .height('90%') 192 .width('100%') 193 .allowDrop([uniformTypeDescriptor.UniformDataType.TEXT]) 194 .onDrop((event?: DragEvent, extraParams?: string) => { 195 this.uri = JSON.parse(extraParams as string).extraInfo; 196 this.AblockArr.splice(JSON.parse(extraParams as string).insertIndex, 0, this.uri); 197 console.log("ondrop not udmf data"); 198 }) 199 .border({width: 1}) 200 } 201 .height("50%") 202 .width("45%") 203 .border({ width: 1 }) 204 .margin({ left: 12 }) 205 Column(){ 206 Text('可释放区域') 207 .fontSize('15dp') 208 .height('10%') 209 List(){ 210 ForEach(this.BblockArr, (item:string, index) => { 211 ListItem() { 212 Image(item) 213 .width(100) 214 .height(100) 215 .border({width: 1}) 216 } 217 .margin({ left: 30 , top : 30}) 218 }, (item:string) => item) 219 } 220 .border({width: 1}) 221 .height('90%') 222 .width('100%') 223 .allowDrop([uniformTypeDescriptor.UniformDataType.IMAGE]) 224 .onDrop((event?: DragEvent, extraParams?: string) => { 225 console.log("enter onDrop") 226 let dragData:UnifiedData = (event as DragEvent).getData() as UnifiedData; 227 if(dragData != undefined) { 228 let arr:Array<unifiedDataChannel.UnifiedRecord> = dragData.getRecords(); 229 if(arr.length > 0) { 230 let image = arr[0] as unifiedDataChannel.Image; 231 this.uri = image.imageUri; 232 this.BblockArr.splice(JSON.parse(extraParams as string).insertIndex, 0, this.uri); 233 } else { 234 console.log(`dragData arr is null`) 235 } 236 } else { 237 console.log(`dragData is undefined`) 238 } 239 console.log("ondrop udmf data"); 240 this.dragSuccess = true 241 }) 242 } 243 .height("50%") 244 .width("45%") 245 .border({ width: 1 }) 246 .margin({ left: 12 }) 247 } 248 }.width('100%') 249 } 250} 251``` 252 253 254 255### 示例2(设置预览图) 256 257该示例通过配置dragPreview设置拖拽过程的预览图。 258 259```ts 260// xxx.ets 261@Entry 262@Component 263struct DragPreviewDemo{ 264 @Builder dragPreviewBuilder() { 265 Column() { 266 Text("dragPreview") 267 .width(150) 268 .height(50) 269 .fontSize(20) 270 .borderRadius(10) 271 .textAlign(TextAlign.Center) 272 .fontColor(Color.Black) 273 .backgroundColor(Color.Pink) 274 } 275 } 276 277 @Builder MenuBuilder() { 278 Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { 279 Text("menu item 1") 280 .fontSize(15) 281 .width(100) 282 .height(40) 283 .textAlign(TextAlign.Center) 284 .fontColor(Color.Black) 285 .backgroundColor(Color.Pink) 286 Divider() 287 .height(5) 288 Text("menu item 2") 289 .fontSize(15) 290 .width(100) 291 .height(40) 292 .textAlign(TextAlign.Center) 293 .fontColor(Color.Black) 294 .backgroundColor(Color.Pink) 295 } 296 .width(100) 297 } 298 299 build() { 300 Row() { 301 Column() { 302 Image('/resource/image.jpeg') 303 .width("30%") 304 .draggable(true) 305 .bindContextMenu(this.MenuBuilder, ResponseType.LongPress) 306 .onDragStart(() => { 307 console.log("Image onDragStart") 308 }) 309 .dragPreview(this.dragPreviewBuilder) 310 } 311 .width("100%") 312 } 313 .height("100%") 314 } 315} 316``` 317 318 319 320### 示例3(设置背板图样式) 321 322该示例通过配置dragPreviewOptions为ENABLE_DEFAULT_SHADOW和ENABLE_DEFAULT_RADIUS设置默认阴影和统一圆角效果。 323 324```ts 325// xxx.ets 326@Entry 327@Component 328struct dragPreviewOptionsDemo{ 329 build() { 330 Row() { 331 Column() { 332 Image('/resource/image.jpeg') 333 .margin({ top: 10 }) 334 .width("100%") 335 .draggable(true) 336 .dragPreviewOptions({ mode: DragPreviewMode.AUTO }) 337 Image('/resource/image.jpeg') 338 .margin({ top: 10 }) 339 .width("80%") 340 .border({ radius: { topLeft: 1, topRight: 2, bottomLeft: 4, bottomRight: 8 } }) 341 .draggable(true) 342 .dragPreviewOptions({ mode: [ DragPreviewMode.ENABLE_DEFAULT_SHADOW, DragPreviewMode.ENABLE_DEFAULT_RADIUS ] }) 343 } 344 .width("100%") 345 .height("100%") 346 } 347 } 348} 349``` 350 351 352 353 354### 示例4(设置多选拖拽) 355 356该示例通过配置isMultiSelectionEnabled实现Grid组件的多选拖拽效果。 357 358```ts 359@Entry 360@Component 361struct Example { 362 @State numbers: number[] = [0, 1, 2, 3, 4 , 5, 6, 7, 8] 363 build() { 364 Column({ space: 5}) { 365 Grid() { 366 ForEach(this.numbers, (item: number) => { 367 GridItem() { 368 Column() 369 .backgroundColor(Color.Blue) 370 .width('100%') 371 .height('100%') 372 } 373 .width(90) 374 .height(90) 375 .selectable(true) 376 .selected(true) 377 .dragPreviewOptions({}, {isMultiSelectionEnabled:true}) 378 .onDragStart(()=>{ 379 380 }) 381 }, (item: string) => item) 382 } 383 .columnsTemplate('1fr 1fr 1fr') 384 .rowsTemplate('1fr 1fr 1fr') 385 .height(300) 386 } 387 .width('100%') 388 } 389} 390``` 391 392 393 394### 示例5(设置默认点按效果) 395 396该示例通过配置defaultAnimationBeforeLifting实现Grid组件的默认点按效果。 397 398```ts 399@Entry 400@Component 401struct Example { 402 @State numbers: number[] = [0, 1, 2, 3, 4 , 5, 6, 7, 8] 403 build() { 404 Column({ space: 5}) { 405 Grid() { 406 ForEach(this.numbers, (item: number) => { 407 GridItem() { 408 Column() 409 .backgroundColor(Color.Blue) 410 .width('100%') 411 .height('100%') 412 } 413 .width(90) 414 .height(90) 415 .selectable(true) 416 .selected(true) 417 .dragPreviewOptions({}, {isMultiSelectionEnabled:true, defaultAnimationBeforeLifting:true}) 418 .onDragStart(()=>{ 419 420 }) 421 }, (item: string) => item) 422 } 423 .columnsTemplate('1fr 1fr 1fr') 424 .rowsTemplate('1fr 1fr 1fr') 425 .height(300) 426 } 427 .width('100%') 428 } 429} 430``` 431 432 433 434### 示例6(自定义背板图样式) 435 436该示例通过配置ImageModifier实现Image组件的自定义背板图样式。 437 438```ts 439// xxx.ets 440import { ImageModifier } from '@kit.ArkUI' 441 442@Entry 443@Component 444struct dragPreviewOptionsDemo{ 445 @State myModifier: ImageAttribute = new ImageModifier().opacity(0.5) 446 @State vis: boolean = true 447 @State changeValue: string = '' 448 @State submitValue: string = '' 449 @State positionInfo: CaretOffset = { index: 0, x: 0, y: 0 } 450 controller: SearchController = new SearchController() 451 @State OpacityIndex: number = 0 452 @State OpacityList:(number | undefined | null)[]=[ 453 0.3,0.5,0.7,1,-50,0,10,undefined,null 454 ] 455 build() { 456 Row() { 457 Column() { 458 Text(this.OpacityList[this.OpacityIndex] + "") 459 Button("Opacity") 460 .onClick(()=> { 461 this.OpacityIndex++ 462 if(this.OpacityIndex > this.OpacityList.length - 1){ 463 this.OpacityIndex = 0 464 } 465 }) 466 Image($r('app.media.image')) 467 .margin({ top: 10 }) 468 .width("100%") 469 .draggable(true) 470 .dragPreviewOptions({modifier: this.myModifier.opacity(this.OpacityList[this.OpacityIndex]) as ImageModifier}) 471 } 472 .width("50%") 473 .height("50%") 474 } 475 } 476} 477``` 478 479 480 481### 示例7(图片拖拽设置) 482 483该示例展示了不同图片(在线图片资源、本地图片资源和PixelMap)在拖拽时组件的设置。 484使用网络图片时,需要申请权限ohos.permission.INTERNET。具体申请方式请参考[声明权限](../../../security/AccessToken/declare-permissions.md)。 485 486```ts 487// xxx.ets 488import { uniformTypeDescriptor, unifiedDataChannel } from '@kit.ArkData'; 489import { image } from '@kit.ImageKit'; 490import { request } from '@kit.BasicServicesKit'; 491import { common } from '@kit.AbilityKit'; 492import { fileIo } from '@kit.CoreFileKit'; 493import { buffer } from '@kit.ArkTS'; 494import { BusinessError } from '@kit.BasicServicesKit'; 495 496@Entry 497@Component 498struct ImageDrag { 499 @State targetImage1: string | PixelMap | null = null; 500 @State targetImage2: string | PixelMap | null = null; 501 @State targetImage3: string | PixelMap | null = null; 502 context = getContext(this) as common.UIAbilityContext; 503 filesDir = this.context.filesDir; 504 505 public async createPixelMap(pixelMap: unifiedDataChannel.SystemDefinedPixelMap): Promise<image.PixelMap | null> { 506 let mWidth: number = (pixelMap.details?.width ?? -1) as number; 507 let mHeight: number = (pixelMap.details?.width ?? -1) as number; 508 let mPixelFormat: image.PixelMapFormat = 509 (pixelMap.details?.['pixel-format'] ?? image.PixelMapFormat.UNKNOWN) as image.PixelMapFormat; 510 let mItemPixelMapData: Uint8Array = pixelMap.rawData; 511 const opts: image.InitializationOptions = { 512 editable: false, pixelFormat: mPixelFormat, size: { 513 height: mHeight, 514 width: mWidth 515 } 516 }; 517 const buffer: ArrayBuffer = mItemPixelMapData.buffer.slice(mItemPixelMapData.byteOffset, 518 mItemPixelMapData.byteLength + mItemPixelMapData.byteOffset); 519 try { 520 let pixelMap: image.PixelMap = await image.createPixelMap(buffer, opts); 521 return pixelMap; 522 } catch (err) { 523 console.error('dragtest--> getPixelMap', err); 524 return null; 525 } 526 } 527 528 build() { 529 Column() { 530 Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Center }) { 531 // 在线图片资源拖出 532 Column() { 533 Text('Online Image').fontSize(14) 534 Image('https://www.example.com/xxx.png') // 请填写一个具体的网络图片地址 535 .objectFit(ImageFit.Contain).draggable(true) 536 .onDragStart(() => {}) 537 .width(100).height(100) 538 } 539 .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted }) 540 .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center) 541 542 // 本地图片资源拖出 543 Column() { 544 Text('Local Image').fontSize(14) 545 Image($r('app.media.example')) 546 .objectFit(ImageFit.Contain).draggable(true) 547 .onDragStart(() => {}) 548 .width(100).height(100) 549 } 550 .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted }) 551 .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center) 552 553 // PixelMap拖出 554 Column() { 555 Text('PixelMap').fontSize(14) 556 Image(this.context.resourceManager.getDrawableDescriptor($r('app.media.example').id).getPixelMap()) 557 .objectFit(ImageFit.Contain).draggable(true) 558 .onDragStart(() => {}) 559 .width(100).height(100) 560 } 561 .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted }) 562 .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center) 563 } 564 565 // 落入数据类型为Image 566 Text('Data type is Image').fontSize(14).margin({ top: 10 }) 567 Column() { 568 Image(this.targetImage1) 569 .objectFit(ImageFit.Contain) 570 .width('70%').height('70%') 571 .allowDrop([uniformTypeDescriptor.UniformDataType.IMAGE]) 572 .onDrop((event: DragEvent, extraParams: string) => { 573 // 通过extraParams获取图片 574 let arr: Record<string, object> = JSON.parse(extraParams) as Record<string, object>; 575 let uri = arr['extraInfo']; 576 if (typeof uri == 'string') { 577 this.targetImage1 = uri; 578 579 try { 580 request.downloadFile(this.context, { 581 url: uri, 582 filePath: this.filesDir + '/example.png' 583 }).then((downloadTask: request.DownloadTask) => { 584 let file = fileIo.openSync(this.filesDir + '/example.png', fileIo.OpenMode.READ_WRITE); 585 let arrayBuffer = new ArrayBuffer(1024); 586 let readLen = fileIo.readSync(file.fd, arrayBuffer); 587 let buf = buffer.from(arrayBuffer, 0, readLen); 588 console.info(`The content of file: ${buf.toString()}`); 589 fileIo.closeSync(file); 590 }) 591 } catch (error) {} 592 } 593 }) 594 } 595 .width('70%').height('25%') 596 .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted }) 597 .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center) 598 599 Column() { 600 Image(this.targetImage2) 601 .objectFit(ImageFit.Contain) 602 .width('70%').height('70%') 603 .allowDrop([uniformTypeDescriptor.UniformDataType.IMAGE]) 604 .onDrop((event: DragEvent, extraParams: string) => { 605 // 通过uniformTypeDescriptor获取图片 606 let data: UnifiedData = event.getData(); 607 let records: Array<unifiedDataChannel.UnifiedRecord> = data.getRecords(); 608 if (records[0].getType() ===uniformTypeDescriptor.UniformDataType.IMAGE) { 609 let image: unifiedDataChannel.Image = records[0] as unifiedDataChannel.Image; 610 this.targetImage2 = image.imageUri; 611 } 612 }) 613 } 614 .width('70%').height('25%') 615 .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted }) 616 .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center) 617 618 // 落入数据类型为PixelMap 619 Text('Data type is PixelMap').fontSize(14).margin({ top: 10 }) 620 Column() { 621 Image(this.targetImage3) 622 .objectFit(ImageFit.Contain) 623 .width('70%').height('70%') 624 .allowDrop([uniformTypeDescriptor.UniformDataType.OPENHARMONY_PIXEL_MAP]) 625 .onDrop(async (event: DragEvent, extraParams: string) => { 626 // 通过uniformTypeDescriptor获取图片 627 let data: UnifiedData = event.getData(); 628 let records: Array<unifiedDataChannel.UnifiedRecord> = data.getRecords(); 629 if (records[0].getType() ===uniformTypeDescriptor.UniformDataType.OPENHARMONY_PIXEL_MAP) { 630 let record: unifiedDataChannel.SystemDefinedPixelMap = records[0] as unifiedDataChannel.SystemDefinedPixelMap; 631 this.targetImage3 = await this.createPixelMap(record); 632 633 // 落盘到本地 634 const imagePackerApi = image.createImagePacker(); 635 let packOpts : image.PackingOption = { format: "image/jpeg", quality:98 }; 636 const path : string = this.context.cacheDir + "/pixel_map.jpg"; 637 let file = fileIo.openSync(path, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE); 638 imagePackerApi.packToFile(this.targetImage3, file.fd, packOpts).then(() => { 639 // 直接打包进文件 640 }).catch((error : BusinessError) => { 641 console.error('Failed to pack the image. And the error is: ' + error); 642 }) 643 } 644 }) 645 } 646 .width('70%').height('25%') 647 .border({ width: 2, color: Color.Gray, radius: 5, style: BorderStyle.Dotted }) 648 .alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center) 649 650 }.width('100%').height('100%') 651 } 652} 653``` 654 655 656 657### 示例8(自定义预览图) 658该示例通过配置onlyForLifting实现自定义预览图,仅用于浮起效果以及配置isLiftingDisabled实现禁用浮起效果。 659```ts 660// xxx.ets 661@Entry 662@Component 663struct LiftingExampleDemo { 664 @Builder 665 dragPreviewBuilder() { 666 Column() { 667 Text("dragPreview builder") 668 .width(150) 669 .height(50) 670 .fontSize(20) 671 .borderRadius(10) 672 .textAlign(TextAlign.Center) 673 .fontColor(Color.Black) 674 .backgroundColor(Color.Green) 675 } 676 } 677 @Builder 678 MenuBuilder() { 679 Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { 680 Text("menu 1") 681 .fontSize(25) 682 .width(200) 683 .height(60) 684 .textAlign(TextAlign.Center) 685 .fontColor(Color.Black) 686 .backgroundColor(Color.Green) 687 Divider() 688 .height(5) 689 Text("menu 2") 690 .fontSize(25) 691 .width(200) 692 .height(60) 693 .textAlign(TextAlign.Center) 694 .fontColor(Color.Black) 695 .backgroundColor(Color.Green) 696 } 697 .width(100) 698 } 699 build() { 700 Column() { 701 Column() { 702 Text("禁用浮起效果") 703 .fontSize(30) 704 .height(30) 705 .backgroundColor('#FFFFFF') 706 .margin({ top: 30 }) 707 Image($r('app.media.startIcon')) 708 .width("40%") 709 .draggable(true) 710 .margin({ top: 15 }) 711 .bindContextMenu(this.MenuBuilder, ResponseType.LongPress) 712 .onDragStart(() => { 713 }) 714 .dragPreviewOptions({}, { 715 isLiftingDisabled: true 716 }) 717 .dragPreview(this.dragPreviewBuilder, { 718 onlyForLifting: true, 719 delayCreating: true 720 }) 721 }.width("%") 722 Column() { 723 Text("仅用于浮起效果") 724 .fontSize(30) 725 .height(30) 726 .backgroundColor('#FFFFFF') 727 .margin({ top: 80 }) 728 Image($r('app.media.startIcon')) 729 .width("40%") 730 .draggable(true) 731 .margin({ top: 15 }) 732 .onDragStart(() => { 733 }) 734 .dragPreviewOptions({}, { 735 isLiftingDisabled: false 736 }) 737 .dragPreview(this.dragPreviewBuilder, { 738 onlyForLifting: true, 739 delayCreating: true 740 }) 741 }.width("100%") 742 }.height("100%") 743 } 744} 745``` 746 747自定义预览图用于浮起效果。 748 749 750 751自定义预览图禁用浮起效果。 752 753 754