文档管理中心
FAQ应用框架开发UI框架组件使用实现List头部插入数据时显示的项不变

实现List头部插入数据时显示的项不变

问题现象

当用户在聊天界面上滑时,通常需要从数据库中加载更早的消息,这些消息需要插入到当前消息列表的头部,如果直接将数据插入到头部而不进行其他操作,会使当前正在查看的消息被挤出屏幕。那么如何实现往List数据源数组的头部插入数据时List显示的项不变呢?

效果预览

背景知识

  • onScrollIndex在子组件划入或划出List显示区域时触发,可用于记录List当前项的索引位置。
  • scrollToIndex可以让ListItem滑动到指定Index,支持设置滑动额外偏移量。
  • currentOffset可以获取List当前的滑动偏移量,从而计算scrollToIndex所需的滑动额外偏移量。

解决方案

  1. 通过onScrollIndex记录当前索引位置。
  2. 插入新数据时,使当前Index的值更新为oldIndex+新插入数组长度,调用scrollToIndex接口滑动到更新后的索引处。
  3. 计算滑动额外偏移量:当ListItem一部分显示在可视区域内,一部分显示在可视区域外时,如果只让ListItem滑动到指定Index而不设置额外偏移量,会使当前显示的ListItem轻微滑动到完全显示,有碍阅读观感。因此需要将ListItem在可视区域外的高度作为滑动额外偏移量,使屏幕内容完全不变。完整示例代码如下:

完整示例参考如下:

收起
自动换行
深色代码主题
复制
  1. @Entry
  2. @Component
  3. struct StableList {
  4. @State listData: string[] =
  5. ['item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7', 'item8', 'item9', 'item10'];
  6. scrollerForList: Scroller = new Scroller();
  7. @State ListIndex: number = 0;
  8. @State nextItemIndex: number = 0;
  9. build() {
  10. Column() {
  11. Row() {
  12. Button('头部插入数据')
  13. .onClick(() => this.prependItems())
  14. .margin(10);
  15. Button('滚动到顶部')
  16. .onClick(() => this.scrollerForList.scrollToIndex(0))
  17. .margin(10);
  18. };
  19. List({ space: 20, initialIndex: this.ListIndex, scroller: this.scrollerForList }) {
  20. ForEach(this.listData, (item: string) => {
  21. ListItem() {
  22. Text(item)
  23. .fontSize(20)
  24. .width('100%')
  25. .textAlign(TextAlign.Center)
  26. .backgroundColor('#f5f5f5')
  27. .height(60);
  28. };
  29. }, (item: string) => item);
  30. }
  31. .width('100%')
  32. .height('80%')
  33. .onScrollIndex((firstIndex: number) => {
  34. this.ListIndex = firstIndex;
  35. });
  36. }
  37. .width('100%')
  38. .height('100%');
  39. }
  40. prependItems() {
  41. console.info(`索引${this.ListIndex}`, ` 偏移量${this.scrollerForList.currentOffset().yOffset}`);
  42. const oldIndex: number = this.ListIndex;
  43. const newItems: string[] = [];
  44. for (let i = 0; i < 5; i++) {
  45. newItems.push(`new item${this.nextItemIndex + i}`);
  46. }
  47. this.nextItemIndex += 5;
  48. this.listData = [...newItems, ...this.listData];
  49. // 计算新的位置并滚动
  50. const newListLength: number = newItems.length;
  51. const newIndex: number = oldIndex + newListLength;
  52. this.scrollerForList.scrollToIndex(newIndex, false, undefined,
  53. { extraOffset: { value: this.scrollerForList.currentOffset().yOffset - 80 * oldIndex, unit: 1 } });
  54. }
  55. }
在 FAQ 中进行搜索
请输入您想要搜索的关键词