HarmonyOS 鸿蒙Next实现文件List拖动示例代码
HarmonyOS 鸿蒙Next实现文件List拖动示例代码
介绍
本示例基于显式动画、List组件实现了文件推动、插入效果。
效果预览

使用说明
运行项目前,请执行 ohpm install @ohos/hamock,下载hamock依赖
实现思路
- List手势拖动:
// 以下组合手势为顺序识别,当长按手势事件未正常触发时,则不会出发拖动手势事件
GestureGroup(GestureMode.Sequence,
// 长按
LongPressGesture()
.onAction((event: GestureEvent) => {
this.currentData = item;
this.isLongPress = true;
this.listExchangeCtrl.onLongPress(item);
this.listExchangeCtrl.originListOffsetY = this.listScroller.currentOffset().yOffset;
}),
// 拖动
PanGesture()
.onActionStart(() => {
// 计算list开始拖动的偏移
this.listExchangeCtrl.originListOffsetY = this.listScroller.currentOffset().yOffset;
})
.onActionUpdate((event: GestureEvent) => {
// 计算item移动坐标时,需要算上list滚动的距离
this.listExchangeCtrl.onMove(item, event.offsetY, this.listScroller.currentOffset().yOffset);
let curListOffset = this.listScroller.currentOffset()
// 获取手指信息
let fingerInfo = event.fingerList[0]
let clickPercentY =
(fingerInfo.globalY - Number(this.listArea.globalPosition.y)) / Number(this.listArea.height)
if (clickPercentY > 0.8 && !this.listScroller.isAtEnd()) {
let scrollVelocity = clickPercentY > 0.9 ? 4 : 2
if (this.listMaxScrollOffsetY - curListOffset.yOffset > scrollVelocity + 5) {
this.listScroller.scrollTo({xOffset: 0, yOffset: curListOffset.yOffset += scrollVelocity})
}
} else if (clickPercentY < 0.2 && curListOffset.yOffset >= 0) {
let scrollVelocity = clickPercentY < 0.1 ? 4 : 2
if (curListOffset.yOffset > scrollVelocity + 5) {
this.listScroller.scrollTo({xOffset: 0, yOffset: curListOffset.yOffset -= scrollVelocity})
}
}
})
.onActionEnd((event: GestureEvent) => {
this.listExchangeCtrl.onDrop(item);
this.listExchangeCtrl.originListOffsetY = this.listScroller.currentOffset().yOffset;
})
).onCancel(() => {
if (!this.isLongPress) {
return;
}
this.listExchangeCtrl.onDrop(item);
})
- List Item拖动、放置、改变位置的处理(具体参考ListExchangeCtrl):
// onMove方法
onMove(item: T, offsetY: number): void {
const index: number = this.deductionData.indexOf(item);
this.offsetY = offsetY - this.dragRefOffset + scrollerOffset - this.originListOffsetY;
this.modifier[index].offsetY = this.offsetY;
const direction: number = this.offsetY > 0 ? 1 : -1;
// 触发拖动时,被覆盖子组件缩小与恢复的动画
const curveValue: ICurve = curves.initCurve(Curve.Sharp);
const value: number = curveValue.interpolate(Math.abs(this.offsetY) / ITEM_HEIGHT);
const shrinkScale: number = 1 - value / 10; // 计算缩放比例,value值缩小10倍
if (index < this.modifier.length - 1) { // 当拖拽的时候,被交换的对象会缩放
this.modifier[index + 1].scale = direction > 0 ? shrinkScale : 1;
}
if (index > 0) {
this.modifier[index - 1].scale = direction > 0 ? 1 : shrinkScale;
}
//处理列表项的切换操作
if (Math.abs(this.offsetY) > ITEM_HEIGHT / 2) {
animateTo({ curve: Curve.Friction, duration: ANIMATE_DURATION }, () => {
this.offsetY -= direction * ITEM_HEIGHT;
this.dragRefOffset += direction * ITEM_HEIGHT;
this.modifier[index].offsetY = this.offsetY;
const target = index + direction // 目标位置索引
if (target !== -1 && target <= this.modifier.length) {
this.changeItem(index, target);
}
})
}
}
// onDrop方法
onDrop(item: T): void {
const index: number = this.deductionData.indexOf(item);
this.dragRefOffset = 0;
this.offsetY = 0;
AppStorage.setOrCreate('isLongPress', false);
/**
* 恢复拖动中,被缩小的子组件,并提供动画。
* 通过interpolatingSpring(0, 1, 400, 38)构造插值器弹簧曲线对象初始速度为0,质量为1,刚度为400,阻尼为38
*/
animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
this.state = OperationStatus.DROPPING;
if (index < this.modifier.length - 1) {
this.modifier[index + 1].scale = 1;
}
if (index > 0) {
this.modifier[index - 1].scale = 1;
}
})
/**
* 恢复被拖拽子组件的放大与阴影效果,并提供动画。
* 通过interpolatingSpring(0, 1, 400, 38)构造插值器弹簧曲线对象初始速度为14,质量为1,刚度为170,阻尼为17
*/
animateTo({ curve: curves.interpolatingSpring(14, 1, 170, 17) }, () => {
this.state = OperationStatus.IDLE;
this.modifier[index].hasShadow = false;
this.modifier[index].scale = 1; // 初始化缩放比例
this.modifier[index].offsetY = 0; // 初始化偏移量
})
}
更多关于HarmonyOS 鸿蒙Next实现文件List拖动示例代码的实战教程也可以访问 https://www.itying.com/category-93-b0.html
1 回复
更多关于HarmonyOS 鸿蒙Next实现文件List拖动示例代码的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
HarmonyOS Next中实现文件列表拖动功能,可以使用List组件结合onDragStart和onDragEnd事件来实现。以下是一个简单的示例代码:
import { List, ListItem, Text } from '@ohos/common';
@Entry
@Component
struct FileListDemo {
@State files: string[] = ['File1.txt', 'File2.txt', 'File3.txt'];
build() {
List({ space: 10 }) {
ForEach(this.files, (file, index) => {
ListItem() {
Text(file)
.fontSize(20)
.onDragStart(() => {
console.log(\`Dragging started: \${file}\`);
return true;
})
.onDragEnd(() => {
console.log(\`Dragging ended: \${file}\`);
})
}
})
}
.width('100%')
.height('100%')
}
}
在这个示例中,List组件用于显示文件列表,ListItem表示每个文件项。通过onDragStart和onDragEnd事件,可以捕获拖动的开始和结束动作。onDragStart返回true表示允许拖动操作。

