期望实现这样一个List列表:
实现思路:
// 列表空白Item填充 ListItem().height(this.listHeight - this.lastEmptyItemHeight - 2 * this.spaceHeight)
// 列表底部触底提示Item
ListItem() {
Text('到底啦~~~')
.width('100%')
.fontSize(20)
.textAlign(TextAlign.Center);
}.height(this.bottomTipHeight); .onTouch((event) => {
switch (event.type) {
case TouchType.Down:
// 记录手指初始触摸点,用于计算上滑期间触底提示块的高度
this.startTouchY = event.touches[0].y;
break;
case TouchType.Move:
// 手指上滑期间,动态计算触底提示块高度
if (this.bottomTipHeight < MAX_BOTTOM_TIP_HEIGHT) {
this.bottomTipHeight = Math.min(MAX_BOTTOM_TIP_HEIGHT, this.startTouchY - event.touches[0].y);
console.log(`event.touches[0].y: ${event.touches[0].y.toFixed(2)}, this.currentOffsetY: ${this.startTouchY.toFixed(2)}, tipsHeight: ${this.bottomTipHeight.toFixed(2)}`);
}
break;
case TouchType.Up:
// 手指抬起后,触底提示块高度重置为0
this.getUIContext()?.animateTo({ curve: curves.springMotion() }, () => {
this.bottomTipHeight = 0;
});
} 完整代码如下:
import { curves } from '@kit.ArkUI';
// 底部提示块最大高度
const MAX_BOTTOM_TIP_HEIGHT = 70;
/**
* 列表吸顶
*/
@Entry
@ComponentV2
struct Index {
@Local bottomTipHeight: number = 0; // 底部提示高度
@Local lastEmptyItemHeight: number = 0; // 最后的空白块高度
private listHeight: number = 0; // 列表高度
private startTouchY: number = 0; // 手指触摸屏幕初始纵轴坐标
private spaceHeight: number = 20; // 列表组间距
private timeTable: TimeTable[] = [
{
title: '周一',
projects: ['语 文', '数 学', '英 语', '生 物']
},
{
title: '周二',
projects: ['地 理', '历 史', '政 治']
},
{
title: '周三',
projects: ['物 理', '化 学']
},
{
title: '周四',
projects: ['计算机导论', '软件工程', '编译原理', '计算机网络', '计算机组成原理']
},
{
title: '周五',
projects: ['HarmonyOS开发实战']
}
];
@Builder
itemHead(text: string) {
Text(text)
.fontSize(20)
.backgroundColor(0xAABBCC)
.width('100%')
.padding(10);
}
@Builder
itemFoot(num: number) {
Text('今日共 ' + num + ' 门课程')
.fontSize(16)
.backgroundColor(0xAABBCC)
.width('100%')
.padding(5);
}
build() {
Column() {
List({ space: this.spaceHeight }) {
// 内容列表组
ForEach(this.timeTable, (item: TimeTable, index: number) => {
ListItemGroup({ header: this.itemHead(item.title), footer: this.itemFoot(item.projects.length) }) {
ForEach(item.projects, (project: string) => {
ListItem() {
Text(project)
.width('100%')
.height(100)
.fontSize(20)
.textAlign(TextAlign.Center)
.backgroundColor(0xFFFFFF);
};
}, (item: string) => item);
}
.divider({ strokeWidth: 1, color: Color.Blue })
.onSizeChange((_oldV, newV) => {
// 获取最后一个ListItemGroup高度
if (index === this.timeTable.length - 1) {
this.lastEmptyItemHeight = newV.height?.valueOf() as number;
}
});
});
// 列表空白Item填充
ListItem().height(this.listHeight - this.lastEmptyItemHeight - 2 * this.spaceHeight)
// 列表底部触底提示Item
ListItem() {
Text('到底啦~~~')
.width('100%')
.fontSize(20)
.textAlign(TextAlign.Center);
}.height(this.bottomTipHeight);
}
.edgeEffect(EdgeEffect.None)
.onTouch((event) => {
switch (event.type) {
case TouchType.Down:
// 记录手指初始触摸点,用于计算上滑期间触底提示块的高度
this.startTouchY = event.touches[0].y;
break;
case TouchType.Move:
// 手指上滑期间,动态计算触底提示块高度
if (this.bottomTipHeight < MAX_BOTTOM_TIP_HEIGHT) {
this.bottomTipHeight = Math.min(MAX_BOTTOM_TIP_HEIGHT, this.startTouchY - event.touches[0].y);
console.log(`event.touches[0].y: ${event.touches[0].y.toFixed(2)}, this.currentOffsetY: ${this.startTouchY.toFixed(2)}, tipsHeight: ${this.bottomTipHeight.toFixed(2)}`);
}
break;
case TouchType.Up:
// 手指抬起后,触底提示块高度重置为0
this.getUIContext()?.animateTo({ curve: curves.springMotion() }, () => {
this.bottomTipHeight = 0;
});
}
})
.onSizeChange((_oldV, newV) => {
if (newV && newV.height) {
this.listHeight = newV.height.valueOf() as number;
}
})
.width('90%')
.height('100%')
.sticky(StickyStyle.Header)
.scrollBar(BarState.Off);
}
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM, SafeAreaEdge.TOP])
.width('100%')
.height('100%')
.backgroundColor(0xDCDCDC)
.padding({ top: 5 });
}
}
interface TimeTable {
title: string;
projects: string[];
}