简介

该文主要提供统一拖拽开发中所遇到的一些问题及解答。

FAQ

文字拖拽因默认情况长按之后选中改的仅为按压处的几个字符

若要实现长按选中当前Text组件的全部文本,则可在LongPressGesture 手势中实现回调并结合 Selection 实现该效果。

Text(this.message)
.copyOption(CopyOptions.InApp)
.draggable(true)
. parallelGesture(
LongPressGesture({ repeat: true })
// 由于repeat设置为true,长按动作存在时会连续触发,触发间隔为duration(默认值500ms)
.onAction((event: GestureEvent) => {
this.beginIndex = 0;
this.endIndex = endIndexOfTextContent;
})
.selection(this.beginIndex, this.endIndex)

图片拖拽Image组件是在线资源时拖出后不能正常落位

若Image组件拖出时,其资源文件是在线地址,则需要拖拽落入方实现对在线数据的下载处理逻辑。

http.createHttp().request('xxx',
{
method: http.RequestMethod.GET,
connectTimeout: 60000,
readTimeout: 60000
},
(error: BusinessError, data: http.HttpResponse) => {
let imageData: ArrayBuffer = data?.result as ArrayBuffer
let imageSource: image.ImageSource = image.createImageSource(imageData)
imageSource.getImageInfo((err, data) => {
let opts: image.DecodingOptions = {
editable: true,
desiredSize: {
height: data.size.height,
width: data.size.width
}
}
imageSource.createPixelMap(opts, async (err, pixelMap) => {
if (err) return
const offScreenCanvas = new OffscreenCanvas(data.size.width, data.size.height, LengthMetricsUnit.PX)
const offScreenContext: OffscreenCanvasRenderingContext2D = offScreenCanvas.getContext('2d')
offScreenContext.drawImage(pixelMap, 0, 0, offScreenCanvas.width, offScreenCanvas.height)
offScreenContext.textAlign = 'right'
offScreenContext.fillStyle = 'rgba(255, 255, 255, 0.7)'
offScreenContext.font = vp2px(8) + 'px'
offScreenContext.shadowBlur = 2
offScreenContext.shadowColor = 'rgba(0, 0, 0, 0.3)'
offScreenContext.fillText(`小红书号`, offScreenCanvas.width - vp2px(10), offScreenCanvas.height - vp2px(11))

this.pixelMap = offScreenContext.getPixelMap(0, 0, offScreenCanvas.width, offScreenCanvas.height);
const imagePackerApi = image.createImagePacker();
const context = getContext(this)
let packOpts : image.PackingOption = { format:"image/png", quality:98 };
let pathDir = context.filesDir
let path = '/cache.png'
this.writeFileSync(pathDir, path)
let file = await fs.open(context.filesDir+path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);

拖拽的触发手势长按浮起与长按手势之间存在冲突

长按手势与拖拽发起手势冲突

若组件既需要处理长按手势,有需要支持可拖拽能力(因拖拽行为的触发为长按500ms并移动10vp),则可通过parallelGesture 实现多个手势事件的处理,而不产生冲突。

// xxx.ets
@Entry
@Component
struct LongPressGestureExample {
@State count: number = 0

build() {
Column() {
Text('LongPress onAction:' + this.count).fontSize(28)
.ParallelGesture(
LongPressGesture({ repeat: true })
// 由于repeat设置为true,长按动作存在时会连续触发,触发间隔为duration(默认值500ms)
.onAction((event: GestureEvent) => {
if (event && event.repeat) {
this.count++
}
})
// 长按动作一结束触发
.onActionEnd((event: GestureEvent) => {
this.count = 0
})
)
.onDragStart((event:DragEvent) => {
// 设置拖拽数据和自定义拖拽背板
})
}
.height(200)
.width(300)
.padding(20)
.border({ width: 3 })
.margin(30)
}
}

长按弹窗、弹出子菜单与拖拽手势发起冲突的情况

// xxx.ets
@Entry
@Component
struct LongPressGestureExample {
@State count: number = 0

build() {
Column() {
Text('LongPress onAction:' + this.count).fontSize(28)
.ParallelGesture(
LongPressGesture({ repeat: true })
// 由于repeat设置为true,长按动作存在时会连续触发,触发间隔为duration(默认值500ms)
.onAction((event: GestureEvent) => {
// 弹出子窗或子菜单
})
// 长按动作一结束触发
.onActionEnd((event: GestureEvent) => {
this.count = 0
})
)
.onDragStart((event:DragEvent) => {
// 设置拖拽数据和自定义拖拽背板
})
.onDragMove((event:DragEvent) => {
// 隐藏子窗或子菜单,避免中断拖拽手势
})
.onDrop((event:DragEvent) => {
// 必须监听onDrop事件,否则onDragMove事件回调不会被触发
})
}
.height(200)
.width(300)
.padding(20)
.border({ width: 3 })
.margin(30)
}
}

图文混排数据拖拽落位后与原拖出方排版格式有差异

当前拖拽数据中图文混排数据可通过HTML实现,但拖拽落入方组件可能并非HTML格式,如RichEditor、RichText等。
当前系统能力对各类富文本数据的格式转换能力较弱,不能保证排版样式一致。

文字无法长按选中后再起拖

文字若要长按选中后再起拖,必须要设置copyOptions属性,否则无法触发长按选中逻辑。

Text(this.message)
.copyOption(CopyOptions.InApp)
.draggable(true)

拖拽到文字某些"输入框"后不响应拖拽

因ArkUI默认支持落入的组件包括"Search、TextInput、TextArea、Video",若应用实现时输入框使用的是Text组件实现,则默认不可响应拖拽事件。

若要实现对拖拽事件的响应,则应主动调用allowDrop、onDrop逻辑实现落入。

content: string = "请输入"
Text(this.message)
.allowDrop([
uniformTypeDescriptor.UniformDataType.PLAIN_TEXT, uniformTypeDescriptor.UniformDataType.TEXT])
.onDrop((event:DragEvent) => {
let currentText: unifiedDataChannel.Text = records as unifiedDataChannel.Text;
let text: string = !!currentText.details ? currentText.details['value'] : '';
this.content= this.content.concat(text);
})

文件、图片等拖入到可落入组件(显示绿色+角标)时不能正常落位

显示绿色角标是因为落入方组件在allowDrop列表中刚设置了当前拖拽数据类型,标识支持该类数据的落入。但是具体是否能够成功落位取决于落入组件在onDrop逻辑中是否正确处理了拖拽数据,如未对数据做处理并刷新UI、读取数据失败等情况都有可能导致落位失败。

落入方应用需明确在onDrop逻辑中是否有对当前拖拽数据做处理并刷新UI,并且排查当前拖拽数据是否非法,如无效uri、无效在线地址等情况。

判定当前拖拽的Image是不是在线资源

在起拖端搜索如下日志,有则说明是在线资源

hilog | grep "Get uri authority empty or uri scheme not equals to file."

判定当前拖拽数据类型及Summary

在起拖端,日志中搜索AceDrag.*summary,在起拖端即可看到当前拖拽数据的summary

hilog | grep -E "AceDrag.*summary"
Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐