HarmonyOS鸿蒙Next中使用List组件实现拖拽排序
HarmonyOS鸿蒙Next中使用List组件实现拖拽排序
如何使用List组件实现一个常用的拖拽排序?
实现思路
1、创建一个具名的 class来定义列表项的数据结构。
2、使用 @State 管理一个 CourseItem 类型的数组。
3、使用 List 和 ForEach 渲染列表,ForEach 的 keyGenerator 使用模型实例的唯一ID。
4、手势处理:为每个 ListItem 绑定 PanGesture,在 onActionUpdate 中计算目标位置,在 onActionEnd 中交换数组中的 CourseItem 实例。
5、通过 @State 变量控制被拖拽项和目标位置的样式,并使用 translate 和 animation 实现平滑的动画效果。
使用场景
1、课程管理应用中的学习顺序调整。
2、团队协作工具中的任务优先级排序。
3、灌溉系统中的灌溉顺序排序
等等。
实现效果
长按模块即可拖动。

完整代码
class CourseItem {
public id: number;
public text: string;
constructor(id: number, text: string) {
this.id = id;
this.text = text;
}
}
@Entry
@Component
struct DraggableListDemo {
// 使用定义好的 CourseItem class 作为数组元素的类型
[@State](/user/State) listItems: Array<CourseItem> = [
new CourseItem(1, '鸿蒙开发基础'),
new CourseItem(2, 'ArkTS语法详解'),
new CourseItem(3, '组件与布局'),
new CourseItem(4, '状态管理'),
new CourseItem(5, '动画与手势'),
new CourseItem(6, '网络与数据持久化'),
new CourseItem(7, '性能优化实践')
];
[@State](/user/State) draggingIndex: number = -1;
[@State](/user/State) dragOffsetY: number = 0;
[@State](/user/State) draggingOverIndex: number = -1;
private readonly ITEM_HEIGHT: number = 80;
build() {
Column() {
Text('拖拽课程以调整顺序')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 20 })
List({ space: 10 }) {
// ForEach 中使用 CourseItem 类型
ForEach(this.listItems, (item: CourseItem, index: number) => {
ListItem() {
this.ListItemBuilder(item, index)
}
// keyGenerator 使用 item 的 id,确保唯一性和稳定性
}, (item: CourseItem) => item.id.toString())
}
.listDirection(Axis.Vertical)
.edgeEffect(EdgeEffect.Spring)
.layoutWeight(1)
.padding({ left: 12, right: 12 })
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
@Builder
// Builder 方法的参数也使用 CourseItem 类型
ListItemBuilder(item: CourseItem, index: number) {
Row() {
Text(item.text)
.fontSize(18)
.fontColor('#333333')
}
.width('100%')
.height(this.ITEM_HEIGHT)
.padding({ left: 16, right: 16 })
.backgroundColor(this.draggingIndex === index ? '#FFE0B2' : (this.draggingOverIndex === index ? '#E1F5FE' : '#FFFFFF'))
.borderRadius(12)
.justifyContent(FlexAlign.Start)
.alignItems(VerticalAlign.Center)
.shadow({
radius: this.draggingIndex === index ? 8 : 2,
color: '#1A000000',
offsetX: 0,
offsetY: this.draggingIndex === index ? 4 : 1
})
.translate({
y: this.draggingIndex === index ? this.dragOffsetY : 0
})
.animation({
duration: 250,
curve: Curve.EaseInOut,
delay: 0
})
.gesture(
PanGesture({ fingers: 1, direction: PanDirection.Vertical })
.onActionStart((event: GestureEvent) => {
this.draggingIndex = index;
this.dragOffsetY = 0;
})
.onActionUpdate((event: GestureEvent) => {
this.dragOffsetY = event.offsetY;
const totalOffset = this.dragOffsetY;
const targetIndex = Math.round(totalOffset / this.ITEM_HEIGHT) + index;
if (targetIndex < 0 || targetIndex >= this.listItems.length || targetIndex === index) {
this.draggingOverIndex = -1;
return;
}
this.draggingOverIndex = targetIndex;
})
.onActionEnd(() => {
if (this.draggingOverIndex !== -1 && this.draggingIndex !== this.draggingOverIndex) {
// 5. 操作的是 CourseItem 实例数组
const newList = [...this.listItems];
const draggedItem = newList[this.draggingIndex];
newList.splice(this.draggingIndex, 1);
newList.splice(this.draggingOverIndex, 0, draggedItem);
this.listItems = newList;
}
this.draggingIndex = -1;
this.draggingOverIndex = -1;
this.dragOffsetY = 0;
})
)
}
}
更多关于HarmonyOS鸿蒙Next中使用List组件实现拖拽排序的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,使用List组件实现拖拽排序主要依赖ArkUI的拖拽事件和List组件的onDragStart、onDragEnter、onDrop事件。通过设置List的editMode属性为true启用编辑模式,结合ListItem的draggable属性为true使项目可拖拽。在拖拽过程中,通过事件回调获取拖拽起始和目标位置索引,并操作List的数据源数组完成数据交换,从而实现视觉上的排序效果。
在HarmonyOS Next中,使用List组件实现拖拽排序,主要依赖ListItem组件的onDragStart、onDragEnter和onDrop事件。以下是核心实现步骤:
-
数据与状态准备:使用
@State装饰器管理列表数据源,并准备一个变量(如fromIndex)记录拖拽起始位置。 -
启动拖拽:在
ListItem上设置onDragStart事件,当用户长按列表项时触发,在此事件中记录被拖拽项的索引,并调用dragControl.start()方法启动拖拽。.onDragStart((event: DragEvent) => { this.fromIndex = index; // 记录拖拽起始索引 event.promise = dragControl.start(); // 启动拖拽 }) -
处理拖拽进入:为
ListItem设置onDragEnter事件。当拖拽项进入其他列表项区域时,交换数据源中fromIndex与当前进入项索引toIndex对应的数据,并更新fromIndex为toIndex,以实现视觉上的实时位置交换。.onDragEnter((event: DragEvent) => { // 交换数据源中 fromIndex 和 toIndex 的数据 let temp = this.dataArray[this.fromIndex]; this.dataArray[this.fromIndex] = this.dataArray[index]; this.dataArray[index] = temp; this.fromIndex = index; // 更新起始索引为当前位置 }) -
处理放置:在
ListItem或整个List上设置onDrop事件。当用户释放拖拽项时,执行最终的数据交换(如果之前实时交换已满足需求,此处可能仅需重置状态),并调用dragControl.finish()结束拖拽。.onDrop((event: DragEvent) => { // 可在此处执行最终的同步逻辑(如果与onDragEnter逻辑重复,可省略或做清理) event.promise = dragControl.finish(); // 结束拖拽 })
关键点:
- 拖拽的视觉反馈(如半透明效果)通常由系统自动处理。
- 数据交换逻辑是核心,需在
onDragEnter中实时更新@State数据驱动UI刷新。 - 确保
dragControl的start与finish方法配对调用。
此方案通过数据驱动实现了List的拖拽排序交互。

