鸿蒙应用开发实战:轻松实现列表上拉加载更多

这是一个使用鸿蒙技术开发的本地原生记账应用,非常适合大家用来练手。相关源码已上传至 Github,点击此处查看项目。欢迎大家交流、指正,也欢迎提交 PR。

一、引言

在移动应用开发中,列表的"上拉加载更多"是一个极其常见的交互模式。当用户滑动列表到底部时,自动加载下一页数据,能够极大地提升用户体验。在鸿蒙(HarmonyOS)应用开发中,实现这一效果同样非常便捷。

本文将带你从零开始,手把手实现一个带有"正在加载中"提示的上拉加载效果,让你快速掌握其核心实现原理。

二、效果预览与核心思路

我们先来看一下最终要实现的效果:当列表滑动到底部时,底部会显示一个"正在加载中..."的提示,模拟网络请求完成后,新的数据被追加到列表中,加载提示消失。

实现这个效果,主要依赖以下几个核心点:

  1. List 组件:作为列表的容器,提供滚动和布局能力。
  2. onReachEnd 事件List 组件提供的一个回调事件,当列表滚动到底部时自动触发。
  3. 状态管理 :通过一个 @State 变量来控制"加载中"状态的显示与隐藏。
  4. 数据模拟 :使用 setTimeout 模拟异步网络请求。

三、代码实现与详解

下面我们直接进入代码环节,看看如何一步步构建这个功能。

3.1 定义数据与状态

首先,我们需要定义列表的数据源和一个用于标识加载状态的状态变量。

typescript 复制代码
@Entry
@Component
struct PullUpLoadDemo {
  // 列表数据源
  @State private listData: string[] = [];
  // 是否正在加载中
  @State private isLoading: boolean = false;

  aboutToAppear() {
    // 初始化时加载第一页数据
    this.loadMoreData();
  }

  // 模拟加载更多数据
  loadMoreData() {
    // 模拟网络请求延迟
    setTimeout(() => {
      // 生成新的数据项
      let newData: string[] = [];
      for (let i = 0; i < 10; i++) {
        newData.push(`列表项 ${this.listData.length + i + 1}`);
      }
      // 将新数据追加到现有数据中
      this.listData = [...this.listData, ...newData];
      // 加载完成,更新状态
      this.isLoading = false;
    }, 1500); // 模拟1.5秒的网络延迟
  }

  build() {
    // ... 构建UI
  }
}

3.2 构建列表 UI

接下来,在 build 方法中构建我们的列表 UI。关键在于 List 组件的 onReachEnd 事件。

typescript 复制代码
  build() {
    Column() {
      List() {
        // 1. 使用 ForEach 渲染数据列表
        ForEach(this.listData, (item: string) => {
          ListItem() {
            Text(item)
              .width('100%')
              .height(80)
              .fontSize(18)
              .textAlign(TextAlign.Center)
              .backgroundColor(Color.White)
              .borderRadius(10)
              .margin({ top: 10 })
          }
        }, (item: string) => item)

        // 2. 在列表末尾添加"加载中"提示项
        if (this.isLoading) {
          ListItem() {
            Row() {
              LoadingProgress()
                .width(24)
                .height(24)
                .margin({ right: 10 })
              Text('正在加载中...')
                .fontSize(16)
                .fontColor('#666')
            }
            .justifyContent(FlexAlign.Center)
            .width('100%')
            .height(60)
          }
        }
      }
      .width('100%')
      .height('100%')
      .backgroundColor('#F5F5F5')
      // 3. 核心:监听列表滚动到底部事件
      .onReachEnd(() => {
        // 如果当前正在加载,则直接返回,避免重复请求
        if (this.isLoading) {
          return;
        }
        // 设置加载状态为 true,显示加载提示
        this.isLoading = true;
        // 调用加载数据的方法
        this.loadMoreData();
      })
    }
    .width('100%')
    .height('100%')
    .padding(10)
  }

四、完整代码示例

为了方便你直接运行和测试,这里提供完整的代码片段。

typescript 复制代码
@Entry
@Component
struct PullUpLoadDemo {
  @State private listData: string[] = [];
  @State private isLoading: boolean = false;

  aboutToAppear() {
    this.loadMoreData();
  }

  loadMoreData() {
    setTimeout(() => {
      let newData: string[] = [];
      for (let i = 0; i < 10; i++) {
        newData.push(`列表项 ${this.listData.length + i + 1}`);
      }
      this.listData = [...this.listData, ...newData];
      this.isLoading = false;
    }, 1500);
  }

  build() {
    Column() {
      List() {
        ForEach(this.listData, (item: string) => {
          ListItem() {
            Text(item)
              .width('100%')
              .height(80)
              .fontSize(18)
              .textAlign(TextAlign.Center)
              .backgroundColor(Color.White)
              .borderRadius(10)
              .margin({ top: 10 })
          }
        }, (item: string) => item)

        if (this.isLoading) {
          ListItem() {
            Row() {
              LoadingProgress()
                .width(24)
                .height(24)
                .margin({ right: 10 })
              Text('正在加载中...')
                .fontSize(16)
                .fontColor('#666')
            }
            .justifyContent(FlexAlign.Center)
            .width('100%')
            .height(60)
          }
        }
      }
      .width('100%')
      .height('100%')
      .backgroundColor('#F5F5F5')
      .onReachEnd(() => {
        if (this.isLoading) {
          return;
        }
        this.isLoading = true;
        this.loadMoreData();
      })
    }
    .width('100%')
    .height('100%')
    .padding(10)
  }
}

运行效果:

五、总结

通过以上步骤,我们成功地在鸿蒙应用中实现了列表的上拉加载更多功能。核心逻辑可以总结为:

  1. 监听事件 :利用 List 组件的 onReachEnd 事件监听滚动到底部。
  2. 状态控制 :通过 isLoading 状态变量防止重复加载,并控制加载提示的显示。
  3. 数据追加:在模拟的异步请求完成后,将新数据追加到原有数据源中。

这个模式非常通用,你可以轻松地将它应用到实际项目中的分页数据加载场景。希望这篇教程对你有所帮助!

相关推荐
梦想不只是梦与想9 分钟前
鸿蒙应用api的兼容性:参数配置(二)
harmonyos·sdk版本·sdkversion
Fluxart.ai11 分钟前
电商商品图审核怎么自动化?规则引擎、人工复核与发布门禁
java·前端·自动化
why技术21 分钟前
AI 写的文章,可能都带着手敲一遍都去不掉的“隐形水印”。
前端·人工智能·后端
愚公搬代码40 分钟前
【愚公系列】《Android应用案例开发大全》016-LBS类应用掌上杭州(辅助工具类的开发)
android·前端
CodeSheep43 分钟前
又一个华为天才少年,离职了!
前端·后端·程序员
kyriewen1 小时前
面试官说"打开你的AI工具"——我才发现,他考的根本不是写代码
前端·人工智能·面试
IT_陈寒2 小时前
Vue的双向绑定把我坑惨了,原来这个场景不能用
前端·人工智能·后端
hunterandroid3 小时前
[Android 从零到一] Compose LazyColumn 性能优化:key、稳定性与重组治理
android·前端
lichenyang4533 小时前
从一次团队邀请开始:用 React、NestJS 与 Socket.IO 做可靠的实时通知
前端
vtian3 小时前
一篇文章吃透 Monorepo:pnpm + Turborepo + Changesets 全流程实战(含 8 个踩坑)
前端