当前位置:   article > 正文

OpenHarmony开发实战:新闻数据加载(ArkTS)_arkts 上拉加载

arkts 上拉加载

本篇Codelab是基于ArkTS的声明式开发范式实现的样例,主要介绍了数据请求和touch事件的使用。包含以下功能:

  1. 数据请求。
  2. 列表下拉刷新。
  3. 列表上拉加载。

相关概念

  • List组件:列表包含一系列相同宽度的列表项。
  • Tabs:通过页签进行内容视图切换。
  • TabContent:仅在Tabs中使用,对应一个切换页签的内容视图。
  • 数据请求:提供HTTP数据请求能力。
  • 触摸事件onTouch:触摸动作触发调用该方法。

相关权限

添加网络权限:ohos.permission.INTERNET。

使用说明

服务端搭建流程
  1. 搭建nodejs环境:本篇Codelab的服务端是基于nodejs实现的,需要安装nodejs,如果您本地已有nodejs环境可以跳过此步骤。

    1. 检查本地是否安装nodejs:打开命令行工具(如Windows系统的cmd和Mac电脑的Terminal,这里以Windows为例),输入node -v,如果可以看到版本信息,说明已经安装nodejs。

    2. 如果本地没有nodejs环境,您可以去nodejs官网上下载所需版本进行安装配置。

    3. 配置完环境变量后,重新打开命令行工具,输入node -v,如果可以看到版本信息,说明已安装成功。

  2. 构建局域网环境:测试本Codelab时要确保运行服务端代码的电脑和测试机连接的是同一局域网下的网络,您可以用您的手机开一个个人热点,然后将测试机和运行服务端代码的电脑都连接您的手机热点进行测试。

  3. 运行服务端代码:在本项目的HttpServerOfNews目录下打开命令行工具,输入npm install 安装服务端依赖包,安装成功后输入npm start点击回车。看到“服务器启动成功!”则表示服务端已经在正常运行。

  4. 连接服务器地址:打开命令行工具,输入ipconfig命令查看本地ip,将本地ip地址复制到src/main/ets/common/constant/CommonConstants.ets文件下的23行,注意只替换ip地址部分,不要修改端口号,保存好ip之后即可运行Codelab进行测试。

前端使用说明
  1. 点击应用进入主页面,页面使用tabBar展示新闻分类,tabContent展示新闻列表,新闻分类和新闻列表通过请求nodejs服务端获取。
  2. 点击页签或左右滑动页面,切换标签并展示对应新闻类型的数据。
  3. 新闻列表页面,滑动到新闻列表首项数据,接着往下滑动会触发下拉刷新操作,页面更新初始4条新闻数据,滑动到新闻列表最后一项数据,往上拉会触发上拉加载操作,新闻列表会在后面加载4条新闻数据。

环境搭建

软件要求

  • DevEco Studio版本:DevEco Studio 3.1 Release。
  • OpenHarmony SDK版本:API version 9。

硬件要求

环境搭建

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:

  1. 获取OpenHarmony系统版本:标准系统解决方案(二进制)。以3.2Release版本为例:

  2. 搭建烧录环境。

    1. 完成DevEco Device Tool的安装
    2. 完成RK3568开发板的烧录
  3. 搭建开发环境。

    1. 开始前请参考工具准备,完成DevEco Studio的安装和开发环境配置。
    2. 开发环境配置完成后,请参考使用工程向导创建工程(模板选择“Empty Ability”)。
    3. 工程创建完成后,选择使用真机进行调测

代码结构解读

本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。

  1. ├──entry/src/main/ets // ArkTS代码区
  2. │ ├──common
  3. │ │ ├──constant
  4. │ │ │ └──CommonConstant.ets // 公共常量类
  5. │ │ └──utils
  6. │ │ ├──HttpUtil.ets // 网络请求方法
  7. │ │ ├──Logger.ets // 日志工具类
  8. │ │ ├──PullDownRefresh.ets // 下拉刷新方法
  9. │ │ └──PullUpLoadMore.ets // 上拉加载更多方法
  10. │ ├──entryability
  11. │ │ └──EntryAbility.ts // 程序入口类
  12. │ ├──pages
  13. │ │ └──Index.ets // 主页面
  14. │ ├──view
  15. │ │ ├──CustomRefreshLoadLayout.ets // 下拉刷新、上拉加载布局文件
  16. │ │ ├──LoadMoreLayout.ets // 上拉加载布局封装
  17. │ │ ├──NewsItem.ets // 新闻数据
  18. │ │ ├──NewsList.ets // 新闻列表
  19. │ │ ├──NoMoreLayout.ets // 上拉停止布局封装
  20. │ │ ├──RefreshLayout.ets // 下拉刷新布局封装
  21. │ │ └──TabBar.ets // 新闻类型页签
  22. │ └──viewmodel
  23. │ ├──NewsModel.ets // 新闻模型类
  24. │ └──NewsViewModel.ets // 新闻ViewModel
  25. ├──entry/src/main/resources // 资源文件目录
  26. └──HttpServerOfNews // 服务端代码

构建主界面

本章节将介绍新闻列表页面的实现,用tabBar展示新闻分类,tabContent展示新闻列表,效果图如图所示:

在TabBar.ets文件中的aboutToAppear()方法里获取新闻分类。

  1. // TabBar.ets
  2. aboutToAppear() {
  3. // 请求服务端新闻类别
  4. NewsViewModel.getNewsTypeList().then((typeList: NewsTypeBean[]) => {
  5. this.tabBarArray = typeList;
  6. }).catch((typeList: NewsTypeBean[]) => {
  7. this.tabBarArray = typeList;
  8. });
  9. }

在NewsList.ets文件中的aboutToAppear()方法里获取新闻数据,将数据加载到新闻列表页面ListLayout布局中。

  1. // NewsList.ets
  2. changeCategory() {
  3. this.newsModel.currentPage = 1;
  4. NewsViewModel.getNewsList(this.newsModel.currentPage, this.newsModel.pageSize, Const.GET_NEWS_LIST)
  5. .then((data: NewsData[]) => {
  6. this.newsModel.pageState = PageState.Success;
  7. if (data.length === this.newsModel.pageSize) {
  8. this.newsModel.currentPage++;
  9. this.newsModel.hasMore = true;
  10. } else {
  11. this.newsModel.hasMore = false;
  12. }
  13. this.newsModel.newsData = data;
  14. })
  15. .catch((err: string | Resource) => {
  16. promptAction.showToast({
  17. message: err,
  18. duration: Const.ANIMATION_DURATION
  19. });
  20. this.newsModel.pageState = PageState.Fail;
  21. });
  22. }
  23. aboutToAppear() {
  24. // 请求服务端新闻数据
  25. this.changeCategory();
  26. }
  27. ...
  28. @Builder ListLayout() {
  29. List() {
  30. ...
  31. ForEach(this.newsModel.newsData, (item: NewsData) => {
  32. ListItem() {
  33. // 新闻数据
  34. NewsItem({ newsData: item })
  35. }
  36. .height($r('app.float.news_list_height'))
  37. .backgroundColor($r('app.color.white'))
  38. .margin({ top: $r('app.float.news_list_margin_top') })
  39. .borderRadius(Const.NewsListConstant_ITEM_BORDER_RADIUS)
  40. }, (item: NewsData, index?: number) => JSON.stringify(item) + index)
  41. ...
  42. }
  43. ...
  44. }

数据请求

在module.json5文件中配置如下权限:

  1. // module.json5
  2. "requestPermissions": [
  3. {
  4. "name": "ohos.permission.INTERNET",
  5. "reason": "$string:dependency_reason",
  6. "usedScene": {
  7. "abilities": [
  8. "EntryAbility"
  9. ],
  10. "when": "inuse"
  11. }
  12. }
  13. ]

这一章节,将基于新闻数据请求来介绍如何从服务端请求数据。

导入http模块,封装httpRequestGet方法,调用者传入url地址和所需参数发起网络数据请求。

  1. // HttpUtil.ets
  2. import http from '@ohos.net.http';
  3. ...
  4. export function httpRequestGet(url: string): Promise<ResponseResult> {
  5. let httpRequest = http.createHttp();
  6. // 发送数据请求
  7. let responseResult = httpRequest.request(url, {
  8. method: http.RequestMethod.GET,
  9. readTimeout: Const.HTTP_READ_TIMEOUT,
  10. header: {
  11. 'Content-Type': ContentType.JSON
  12. },
  13. connectTimeout: Const.HTTP_READ_TIMEOUT,
  14. extraData: {}
  15. });
  16. let serverData: ResponseResult = new ResponseResult();
  17. // 处理数据,并返回
  18. return responseResult.then((value: http.HttpResponse) => {
  19. Logger.info(`http value ${JSON.stringify(value)}`);
  20. if (value.responseCode === Const.HTTP_CODE_200) {
  21. // 获取返回数据
  22. let result = `${value.result}`;
  23. let resultJson: ResponseResult = JSON.parse(result);
  24. if (resultJson.code === Const.SERVER_CODE_SUCCESS) {
  25. serverData.data = resultJson.data;
  26. }
  27. serverData.code = resultJson.code;
  28. serverData.msg = resultJson.msg;
  29. } else {
  30. serverData.msg = `${$r('app.string.http_error_message')}&${value.responseCode}`;
  31. }
  32. return serverData;
  33. }).catch(() => {
  34. serverData.msg = $r('app.string.http_error_message');
  35. return serverData;
  36. })
  37. }

在NewsViewModel.ets文件中封装getNewsList方法,调用httpRequestGet方法请求服务端,用Promise异步保存返回的新闻数据列表。

  1. // NewsViewModel.ets
  2. // 获取服务端新闻数据列表
  3. getNewsList(currentPage: number, pageSize: number, path: string): Promise<NewsData[]> {
  4. return new Promise(async (resolve: Function, reject: Function) => {
  5. let url = `${Const.SERVER}/${path}`;
  6. url += '?currentPage=' + currentPage + '&pageSize=' + pageSize;
  7. httpRequestGet(url).then((data: ResponseResult) => {
  8. if (data.code === Const.SERVER_CODE_SUCCESS) {
  9. resolve(data.data);
  10. } else {
  11. Logger.error('getNewsList failed', JSON.stringify(data));
  12. reject($r('app.string.page_none_msg'));
  13. }
  14. }).catch((err: Error) => {
  15. Logger.error('getNewsList failed', JSON.stringify(err));
  16. reject($r('app.string.http_error_message'));
  17. });
  18. });
  19. }

下拉刷新

本章节将以下拉刷新的功能效果来介绍touch事件的使用。效果图如图所示:

创建一个下拉刷新布局CustomLayout,动态传入刷新图片和刷新文字描述。

  1. // CustomRefreshLoadLayout.ets
  2. build() {
  3. Row() {
  4. // 下拉刷新图片
  5. Image(this.customRefreshLoadClass.imageSrc)
  6. ...
  7. // 下拉刷新文字
  8. Text(this.customRefreshLoadClass.textValue)
  9. ...
  10. }
  11. ...
  12. }

将下拉刷新的布局添加到NewsList.ets文件中新闻列表布局ListLayout里面,监听ListLayout组件的onTouch事件实现下拉刷新。

  1. // NewsList.ets
  2. build() {
  3. Column() {
  4. if (this.newsModel.pageState === PageState.Success) {
  5. this.ListLayout()
  6. }
  7. ...
  8. }
  9. ...
  10. .onTouch((event: TouchEvent | undefined) => {
  11. if (event) {
  12. if (this.newsModel.pageState === PageState.Success) {
  13. listTouchEvent(this.newsModel, event);
  14. }
  15. }
  16. })
  17. }
  18. ...
  19. @Builder ListLayout() {
  20. List() {
  21. ListItem() {
  22. RefreshLayout({
  23. refreshLayoutClass: new CustomRefreshLoadLayoutClass(this.newsModel.isVisiblePullDown, this.newsModel.pullDownRefreshImage,
  24. this.newsModel.pullDownRefreshText, this.newsModel.pullDownRefreshHeight)
  25. })
  26. ...
  27. }
  28. }
  29. ...
  30. }
  1. 在onTouch事件中,listTouchEvent方法判断触摸事件是否满足下拉条件。如下listTouchEvent所示:
  2. 在touchMovePullRefresh方法中,我们将对下拉的偏移量与下拉刷新布局的高度进行对比,如果大于布局高度并且在新闻列表的顶部,则表示达到刷新条件。如下touchMovePullRefresh所示:
  3. 在pullRefreshState方法中我们会对下拉刷新布局中的状态图片和描述进行改变,如下pullRefreshState所示:
  4. 当手指松开,才执行刷新操作。
  1. // PullDownRefresh.ets
  2. export function listTouchEvent(newsModel: NewsModel, event: TouchEvent) {
  3. switch (event.type) {
  4. ...
  5. case TouchType.Move:
  6. if ((newsModel.isRefreshing === true) || (newsModel.isLoading === true)) {
  7. return;
  8. }
  9. let isDownPull = event.touches[0].y - newsModel.lastMoveY > 0;
  10. if (((isDownPull === true) || (newsModel.isPullRefreshOperation === true)) && (newsModel.isCanLoadMore === false))
  11. {
  12. // 手指移动,处理下拉刷新
  13. touchMovePullRefresh(newsModel, event);
  14. }
  15. ...
  16. break;
  17. }
  18. }
  19. export function touchMovePullRefresh(newsModel: NewsModel, event: TouchEvent) {
  20. if (newsModel.startIndex === 0) {
  21. newsModel.isPullRefreshOperation = true;
  22. let height = vp2px(newsModel.pullDownRefreshHeight);
  23. newsModel.offsetY = event.touches[0].y - newsModel.downY;
  24. // 滑动偏移量大于下拉刷新布局高度,满足刷新条件。
  25. if (newsModel.offsetY >= height) {
  26. pullRefreshState(newsModel, RefreshState.Release);
  27. newsModel.offsetY = height + newsModel.offsetY * Const.Y_OFF_SET_COEFFICIENT;
  28. } else {
  29. pullRefreshState(newsModel, RefreshState.DropDown);
  30. }
  31. if (newsModel.offsetY < 0) {
  32. newsModel.offsetY = 0;
  33. newsModel.isPullRefreshOperation = false;
  34. }
  35. }
  36. }
  37. export function pullRefreshState(newsModel: NewsModel, state: number) {
  38. switch (state) {
  39. ...
  40. case RefreshState.Release:
  41. newsModel.pullDownRefreshText = $r('app.string.release_refresh_text');
  42. newsModel.pullDownRefreshImage = $r('app.media.ic_pull_up_refresh');
  43. newsModel.isCanRefresh = true;
  44. newsModel.isRefreshing = false;
  45. break;
  46. case RefreshState.Refreshing:
  47. newsModel.offsetY = vp2px(newsModel.pullDownRefreshHeight);
  48. newsModel.pullDownRefreshText = $r('app.string.refreshing_text');
  49. newsModel.pullDownRefreshImage = $r('app.media.ic_pull_up_load');
  50. newsModel.isCanRefresh = true;
  51. newsModel.isRefreshing = true;
  52. break;
  53. case RefreshState.Success:
  54. newsModel.pullDownRefreshText = $r('app.string.refresh_success_text');
  55. newsModel.pullDownRefreshImage = $r('app.media.ic_succeed_refresh');
  56. newsModel.isCanRefresh = true;
  57. newsModel.isRefreshing = true;
  58. break;
  59. ...
  60. default:
  61. break;
  62. }
  63. }

上拉加载也是通过touch事件来实现的,此处不再赘叙,有兴趣的同学可参考代码。

最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。 

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员,可以直接领取这份资料

 获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

鸿蒙(HarmonyOS NEXT)最新学习路线

  •  HarmonOS基础技能

  • HarmonOS就业必备技能 
  •  HarmonOS多媒体技术

  • 鸿蒙NaPi组件进阶

  • HarmonOS高级技能

  • 初识HarmonOS内核 
  • 实战就业级设备开发

 有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

《鸿蒙 (OpenHarmony)开发入门教学视频》

《鸿蒙生态应用开发V2.0白皮书》

图片

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

图片

 《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .……

图片

 《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ……

图片

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

图片

 获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料

总结

总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/789978
推荐阅读
相关标签
  

闽ICP备14008679号