ArkUI 统一拖拽:拖得起来,也要放得明白
【摘要】 今天我们做一个最小拖放 Demo:左边卡片拖起来,右边区域接住它。 拖拽不只是 draggable(true)。用户需要知道什么时候开始拖、什么时候进入目标区域、什么时候放下成功。少了这些反馈,拖拽就会像“东西飘走了”。 参考文档: https://developer.huawei.com/consumer/cn/do
ArkUI 统一拖拽:拖得起来,也要放得明白
今天我们做一个最小拖放 Demo:左边卡片拖起来,右边区域接住它。
拖拽不只是 draggable(true)。用户需要知道什么时候开始拖、什么时候进入目标区域、什么时候放下成功。少了这些反馈,拖拽就会像“东西飘走了”。
参考文档:
- https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-interaction-development-guide-overview
拖动项要打开 draggable
.draggable(true)
.onDragStart((event: DragEvent, extraParams?: string): DragItemInfo => {
let info: DragItemInfo = {
builder: () => {
this.dragPreviewBuilder()
},
extraInfo: 'ArkUI drag demo'
}
return info
})
这里用 builder 做拖拽预览,不引入 PixelMap,也不做跨应用数据。注意不要把组件里的 builder 裸传给拖拽系统,拖拽预览会在稍后的系统流程里被调用,直接裸传容易丢掉组件上下文。我们用 @LocalBuilder 加一层箭头函数包装,先把本页内拖放跑通就够了。
放置区域要给反馈
.onDragEnter(() => {
this.dropActive = true
})
.onDrop(() => {
this.droppedCount += 1
})
onDragEnter、onDragLeave、onDrop 这些回调不是摆设。它们能让目标区域知道自己现在是不是“可以接住”拖拽项。
你更想看哪种拖拽场景:卡片排序、拖到收藏夹,还是文件拖放?不同场景会影响数据结构和反馈方式。
完整示例代码
文件位置:entry/src/main/ets/pages/arkUI/interaction/ArkUIDragDemo.ets
@Entry
@Component
struct ArkUIDragDemo {
@State dragText: string = '长按并拖动左侧卡片,放到右侧区域'
@State dropActive: boolean = false
@State droppedCount: number = 0
private showTip(message: string): void {
this.getUIContext().getPromptAction().showToast({
message: message,
duration: 1200,
bottom: 120
})
}
@LocalBuilder
dragPreviewBuilder() {
Row({ space: 8 }) {
Text('拖拽中')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor('#FFFFFF')
}
.padding({ left: 16, right: 16, top: 10, bottom: 10 })
.borderRadius(18)
.backgroundColor('#111827')
}
@Builder
sectionTitle(title: string, desc: string) {
Column({ space: 6 }) {
Text(title)
.fontSize(19)
.fontWeight(FontWeight.Bold)
.fontColor('#111827')
Text(desc)
.fontSize(13)
.fontColor('#6B7280')
.lineHeight(20)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
}
build() {
Scroll() {
Column({ space: 22 }) {
Column({ space: 8 }) {
Text('ArkUI 统一拖拽')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor('#111827')
Text('拖得起来,也要放得明白')
.fontSize(16)
.fontColor('#4B5563')
Text('拖拽不是只有 draggable。开始拖、进入目标、移动、离开、放下、结束,每一步都应该有明确反馈。')
.fontSize(14)
.fontColor('#6B7280')
.lineHeight(22)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
this.sectionTitle('拖动左侧卡片', 'Demo 只做本页内拖放反馈,不处理跨应用数据,也不接入 UDMF。')
Row({ space: 14 }) {
Column({ space: 10 }) {
Text('拖动项')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor('#FFFFFF')
Text('长按后拖到右侧')
.fontSize(13)
.fontColor('#DBEAFE')
}
.width('45%')
.height(150)
.padding(16)
.borderRadius(18)
.backgroundColor('#2563EB')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Start)
.draggable(true)
.onDragStart((event: DragEvent, extraParams?: string): DragItemInfo => {
this.dragText = 'onDragStart:拖拽开始'
this.showTip('拖拽开始')
let info: DragItemInfo = {
builder: () => {
this.dragPreviewBuilder()
},
extraInfo: 'ArkUI drag demo'
}
return info
})
.onDragEnd((event: DragEvent, extraParams?: string) => {
this.dropActive = false
this.dragText = 'onDragEnd:拖拽流程结束'
this.showTip('拖拽结束')
})
Column({ space: 10 }) {
Text(this.dropActive ? '释放到这里' : '放置区域')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor(this.dropActive ? '#FFFFFF' : '#0F172A')
Text(`已放下 ${this.droppedCount} 次`)
.fontSize(13)
.fontColor(this.dropActive ? '#DCFCE7' : '#64748B')
}
.width('55%')
.height(150)
.padding(16)
.borderRadius(18)
.backgroundColor(this.dropActive ? '#16A34A' : '#FFFFFF')
.border({ width: 1, color: this.dropActive ? '#16A34A' : '#CBD5E1' })
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Start)
.onDragEnter((event: DragEvent, extraParams?: string) => {
this.dropActive = true
this.dragText = 'onDragEnter:进入放置区域'
})
.onDragMove((event: DragEvent, extraParams?: string) => {
this.dragText = 'onDragMove:正在放置区域内移动'
})
.onDragLeave((event: DragEvent, extraParams?: string) => {
this.dropActive = false
this.dragText = 'onDragLeave:离开放置区域'
})
.onDrop((event: DragEvent, extraParams?: string) => {
this.dropActive = false
this.droppedCount += 1
this.dragText = 'onDrop:已经放到目标区域'
this.showTip('放置成功')
})
}
.width('100%')
Text(this.dragText)
.width('100%')
.fontSize(14)
.fontColor('#111827')
.lineHeight(22)
.padding(16)
.borderRadius(14)
.backgroundColor('#FFFFFF')
.border({ width: 1, color: '#E5E7EB' })
}
.width('100%')
.padding(24)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.height('100%')
.backgroundColor('#F8FAFC')
}
}
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)