资讯动态

鸿蒙 ArkTS 实战:拖拽排序 DragSort

发布时间:2026/8/7 11:56:52 来源:尧图企业网站定制
引言如果说示例 49「手势演示」展示了手势的基础用法那么示例 50「拖拽排序」就是手势在「列表交互」中的进阶应用。用户按住列表项上下拖动松开后列表项自动移动到目标位置。这个交互在移动端应用中非常常见——笔记排序、待办事项排序、播放列表排序等场景都需要拖拽排序功能。这个应用的实现核心是**PanGesture与列表数据的联动**拖动手势捕获手指位移。根据位移计算目标位置。使用数组splice方法重新排列列表项。整体替换数组触发ForEach刷新。1. 应用概述与功能「拖拽排序」页面自上而下分为顶部返回栏、可排序列表6 个水果项、底部提示文字。1.1 核心功能清单拖拽排序按住列表项上下拖动松开后自动排序。拖拽视觉反馈正在拖动的条目高亮蓝色背景 蓝色边框。位置计算根据手指位移和条目高度计算目标位置。数组重排使用splice方法将拖动项插入目标位置。Toast 反馈排序完成后提示新位置。1.2 技术要点一览PanGesture 三阶段onActionStart开始→onActionUpdate持续→onActionEnd结束。索引到位置的转换Math.round(dragOffset / itemHeight)将位移转换为目标索引。数组 splice 操作先删除原位置再插入目标位置。数组整体替换this.items arr触发State刷新。拖拽视觉状态dragIdx标记当前拖动项用于高亮显示。2. 核心知识点2.1 State 状态变量Stateitems:string[][苹果,香蕉,橙子,葡萄,西瓜,草莓];StatedragIdx:number-1;StatedragOffset:number0;items列表数据数组初始 6 个水果名。dragIdx当前正在拖动的条目索引-1表示无拖动。dragOffset当前拖动的 Y 轴偏移量vp。2.2 PanGesture 的三阶段.gesture(PanGesture().onActionStart((){this.dragIdxidx;this.dragOffset0;}).onActionUpdate((e:GestureEvent){this.dragOffsete.offsetY;}).onActionEnd((){this.handleDragEnd();}))onActionStart手指按下时触发记录拖动起始索引dragIdx和初始偏移0。onActionUpdate手指移动时持续触发更新偏移量dragOffset。onActionEnd手指松开时触发调用handleDragEnd()处理排序。2.3 handleDragEnd排序核心privatehandleDragEnd():void{if(this.dragIdx0){return;}constitemH:number56;constmove:numberMath.round(this.dragOffset/itemH);lettarget:numberthis.dragIdxmove;if(target0){target0;}if(targetthis.items.length-1){targetthis.items.length-1;}if(target!this.dragIdx){constarr:string[]this.items.slice();consttmp:stringarr[this.dragIdx];arr.splice(this.dragIdx,1);arr.splice(target,0,tmp);this.itemsarr;promptAction.showToast({message:已移动到第 (target1) 位});}this.dragIdx-1;this.dragOffset0;}排序流程有效性检查dragIdx 0时返回。计算目标位置move Math.round(dragOffset / itemH)将像素偏移转换为「移动了几格」。target dragIdx move计算目标索引。边界钳制target限制在[0, items.length - 1]范围内。数组重排arr.splice(dragIdx, 1)从原位置删除拖动项。arr.splice(target, 0, tmp)在目标位置插入。刷新状态this.items arr整体替换。重置拖动状态dragIdx -1、dragOffset 0。2.4 数组 splice 操作.splice(index, 1)删除指定位置的 1 个元素。.splice(index, 0, item)在指定位置插入元素不删除任何元素。两步操作实现了「移动」效果先删除再插入。2.5 视觉反馈.backgroundColor(this.dragIdxidx?#dbe7ff:Color.White).border({width:this.dragIdxidx?2:0,color:#1a6cff})正在拖动的条目dragIdx idx高亮显示浅蓝色背景 蓝色边框。2.6 列表项高度itemH: number 56与列表项的实际高度.height(52) padding大致对应。Math.round(dragOffset / itemH)将位移转换为移动的格数。3. 源码逐段解析3.1 数据初始化6 个水果苹果、香蕉、橙子、葡萄、西瓜、草莓。3.2 列表结构List({ space: 8 })ForEach渲染列表每个条目是 52vp 高的ListItem内部包含序号、名称、拖拽图标「≡」。3.3 拖拽图标每个条目右侧显示「≡」图标24fp浅灰色提示用户可以拖动排序。3.4 拖拽手势每个ListItem绑定PanGesture三阶段分别更新dragIdx/dragOffset或调用handleDragEnd()。3.5 视觉反馈拖动项通过dragIdx idx判断设置不同的背景色和边框。4. 关键实现细节分析4.1 拖拽 vs 排序的两阶段拖拽排序分为两个阶段拖动阶段onActionStart→onActionUpdate实时更新视觉状态。排序阶段onActionEnd一次性计算并执行排序。这种分离的好处是拖动过程流畅只更新视觉状态排序过程准确结束时一次性计算。4.2 位置计算的精度Math.round(dragOffset / itemH)使用四舍五入计算目标位置。这意味着只有当手指移动超过半格高度时才会改变目标位置。如果使用Math.floor则需要移动整整一格才会改变。4.3 数组整体替换this.items arr而不是直接操作原数组。这是 ArkTS 数组状态管理的标准做法——只有变量引用改变才能触发State刷新。4.4 边界处理拖拽到第一行以上或最后一行以下时target会被钳制在[0, length - 1]范围内。这防止了数组越界。4.5 重置拖动状态排序完成后或排序未发生时dragIdx和dragOffset都需要重置为初始值。这确保了下一次拖动的正确起始状态。5. 运行效果与操作指南5.1 运行步骤从入口页导航到「拖拽排序」页面。按住任意列表项如「香蕉」向上或向下拖动。松开手指列表项自动移动到新位置。查看 Toast 提示的新位置。6. 可扩展方向6.1 拖动态动画拖动过程中为目标位置添加插入动画如列表项平滑移动。6.2 多选排序支持多选后批量排序。6.3 持久化排序结果保存到本地下次打开时恢复。6.4 跨列表拖拽支持在两个列表之间拖拽排序。6.5 与手势演示结合添加长按进入「拖拽模式」松开退出的交互。7. 常见问题与调试技巧7.1 列表项不跟随手指当前实现中拖动过程中列表项不会跟随手指移动视觉上固定在原位。如果需要跟随效果需要设置translate属性.translate({ y: this.dragOffset })7.2 排序位置不准确检查itemH是否与实际条目高度匹配。如果条目有 padding 或 border需要相应调整。7.3 快速拖动跳回原位如果快速拖动后直接松手没有移动到新位置target可能等于dragIdx不会触发排序。这是正常行为。7.4 数组越界确认边界钳制逻辑target 0 → 0、target length - 1 → length - 1。8. 总结示例 50「拖拽排序」用约 106 行代码展示了 ArkTS 手势与列表交互的进阶应用。重点回顾PanGesture 三阶段onActionStart→onActionUpdate→onActionEnd。位置转换dragOffset / itemHeight将像素位移转换为索引位移。数组 splice先删除再插入实现移动。视觉反馈拖动项高亮显示。状态管理dragIdx/dragOffset分离拖动状态和数据状态。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价