鸿蒙App开发-网络请求-下拉刷新三方库-底部Tab栏-滚动组件(含源码)

本文介绍一个基于鸿蒙ArkTS开发的App,是一个包含轮播图、文章列表和 Web 页面等功能的多页面应用。

本文主要内容包括:

一、效果图

首页
详情页

  

二、内容简介

1.底部Tab栏和两个页面

        App底部是一个TabBar,点击TabBar可以切换上面的页面。共包含两个页面,一个是“首页” ,另一个是“空白页”。

2.顶部Banner

        App顶部是一个Banner,也叫轮播图,点击轮播图可以跳转到对应的详情页面。

3.List组件

        轮播图下方是一个List组件,点击其中某一项可以跳转详情页面。

4.WebView

使用系统组件@ohos.web.webview 显示网页。同时,此详情页面顶部有一个标题栏,用于显示返回键和标题。

三、实现说明

1.主界面

首先实现主界面,包含一个TabBar和上面的两个页面,以下是主界面代码:

import Constants from '../Constants/Constants'
import Home from './Home';
import EmptyPage from './EmptyPage';
@Entry
@Component
struct Index {@State currentTabIndex: number = 0;tabsController: TabsController;aboutToAppear(){this.tabsController = new TabsController();}@Builder TabBuilder(title: string, index: number, icon: Resource) {Column() {Image(icon).width($r('app.float.mainPage_baseTab_size')).height($r('app.float.mainPage_baseTab_size')).fillColor(this.getTabBarColor(index))Text(title).margin({ top: $r('app.float.mainPage_baseTab_top') }).fontSize($r('app.float.main_tab_fontSize')).fontColor(this.getTabBarColor(index))}.justifyContent(FlexAlign.Center).height($r('app.float.mainPage_barHeight')).width(Constants.FULL_PARENT).onClick(() => {this.currentTabIndex = index;this.tabsController.changeIndex(this.currentTabIndex)})}// 获取选项卡栏颜色getTabBarColor(index: number){if(index == this.currentTabIndex){return Color.Blue;}else{return Color.Gray;}}build() {Tabs({barPosition: BarPosition.End,controller: this.tabsController}) {// 首页TabContent() {Home()}.padding({ left: $r('app.float.mainPage_padding'), right: $r('app.float.mainPage_padding') }).backgroundColor($r('app.color.mainPage_backgroundColor')).tabBar(this.TabBuilder(Constants.HOME_TITLE, Constants.HOME_TAB_INDEX, $r('app.media.ic_bottom_home')))// 项目TabContent() {EmptyPage()}.padding({ left: $r('app.float.mainPage_padding'), right: $r('app.float.mainPage_padding') }).backgroundColor($r('app.color.mainPage_backgroundColor')).tabBar(this.TabBuilder(Constants.EMPTY_TITLE, Constants.EMPTY_TAB_INDEX, $r('app.media.ic_bottom_empty')))}.width(Constants.FULL_PARENT).backgroundColor(Color.White).barHeight($r('app.float.mainPage_barHeight')).barMode(BarMode.Fixed).onChange((index: number) => {this.currentTabIndex = index;})}
}
2.首页

本文主要实现的就是首页,用竖向列包含了Banner组件和ArticleList组件,代码如下:

@Component
export default struct Home {build() {Column() {Banner();ArticleList();}}
}

其中Banner组件代码如下,代码中有具体实现的解释:

// 标记为组件
@Component// 导出名为 Banner 的结构体
export default struct Banner {// Swiper 控制器swiperController: SwiperController = new SwiperController();// 轮播图数据@State bannerData: HomeBannerItemBean[] = [];// 生命周期钩子,在即将显示时调用aboutToAppear() {// 获取轮播图数据this.getData();}// 异步获取轮播图数据async getData(){await HomeViewModel.getHomeBanner(Constants.GET_HOME_BANNER).then((data: HomeBannerItemBean[]) => {// 将获取到的数据赋值给轮播图数据this.bannerData = data;}).catch((err: string | Resource) => {// 如果发生错误,显示提示消息promptAction.showToast({message: err,duration: Constants.ANIMATION_DURATION});});}// 构建界面build() {// 垂直排列的列Column() {// 如果有轮播图数据且数据长度大于 0if(this.bannerData && this.bannerData.length > 0){// 使用 Swiper 组件创建轮播图Swiper(this.swiperController) {// 遍历轮播图数据ForEach(this.bannerData, (banner: HomeBannerItemBean) => {// 显示图片,并设置圆角和点击事件Image(banner.imagePath).borderRadius($r('app.float.home_swiper_borderRadius')).onClick(() => {// 点击事件:跳转到 Web 页面,并传递标题和链接参数router.pushUrl({url: 'pages/WebPage',params: {title: banner.title,src: banner.url}}, router.RouterMode.Single)})}, (img: Resource) => JSON.stringify(img.id))}// 设置轮播图的外边距、自动播放、宽度和高度.margin({top: $r('app.float.home_swiper_margin')}).autoPlay(true).width(Constants.FULL_PARENT).height(200)}}}
}

那么在Banner组件下方的ArticleList组件,代码如下:

// 标记为组件
@Component
// 导出名为 ArticleList 的结构体
export default struct ArticleList {// 是否还有更多数据hasMore: boolean = true;// 当前页码currentPage: number = 0;// 每页数据量pageSize: number = 30;// 文章数据数组@State articleData: ArticleItemData[] = [];// 需绑定列表或宫格组件的滚动控制器private scroller: Scroller = new Scroller();// 生命周期钩子,在即将显示时调用aboutToAppear() {// 获取文章列表数据,参数为 true 表示重置数据this.getArticleList(true);}// @Builder 修饰的私有方法,用于创建列表视图@Builderprivate getListView() {// 使用 List 组件创建列表List({ space: 10, scroller: this.scroller }) {// 遍历文章数据ForEach(this.articleData, (item: ArticleItemData) => {// 使用 ListItem 创建列表项ListItem() {// 使用 Flex 创建布局Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween, }) {// 作者和发布时间Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween, }) {Text(item.author).fontSize(13)Text(Util.dateTime(item.publishTime)).fontSize(13)}.margin({ top: 10, left: 30, right: 30 })// 文章标题Text(item.title).width('100%').fontSize(20).textAlign(TextAlign.Center).fontWeight(FontWeight.Bold).maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis }).margin({ left: 10, right: 10 })// 文章分类Text(item.chapterName).fontSize(13).textAlign(TextAlign.Start).width('100%').margin({ left: 30, bottom: 10 })}.borderRadius($r('app.float.home_list_borderRadius')).backgroundColor(Color.White)}.onClick(() => {// 点击列表项跳转到 Web 页面,传递标题和链接参数router.pushUrl({url: 'pages/WebPage',params: {title: item.title,src: item.link}}, router.RouterMode.Single)})})}// 设置列表的圆角.borderRadius($r('app.float.home_list_borderRadius'))// .divider({ strokeWidth: 1, color: 0x222222 })// 设置列表的边缘效果为无效果.edgeEffect(EdgeEffect.None)// 设置列表宽度和高度为100%.width('100%').height('100%')}// 异步获取文章列表数据async getArticleList(reset: boolean) {await HomeViewModel.getHomeArticleList(this.currentPage, this.pageSize, Constants.GET_HOME_ARTICLE_LIST).then((data: ArticleDataBean) => {// 判断是否还有更多数据if (data.curPage < data.pageCount) {this.currentPage++;this.hasMore = true;} else {this.hasMore = false;}// 根据参数判断是否重置数据if (reset) {this.articleData = data.datas;} else {this.articleData = this.articleData.concat(data.datas);}}).catch((err: string | Resource) => {// 显示错误提示promptAction.showToast({ message: err });})}// 构建界面build() {// 使用 Column 组件创建垂直布局Column() {// 使用 PullToRefresh 组件实现下拉刷新和上拉加载PullToRefresh({customRefresh: null,customLoad: null,data: $articleData, // 数据源数组scroller: this.scroller, // 控制器,负责关闭下拉和上拉customList: () => {// 调用 getListView 方法创建列表视图this.getListView();},onRefresh: () => {return new Promise<string>((resolve, reject) => {// 下拉刷新成功后解析数据,重新获取文章列表数据resolve('下拉刷新成功')this.getArticleList(true);});},onLoadMore: () => {// 上拉加载成功后解析数据,继续获取更多文章列表数据return new Promise<string>((resolve, reject) => {resolve('上拉加载成功')this.getArticleList(false);});}})}.backgroundColor("#efefef") // 设置背景颜色}
}

这个文章列表组件,使用了 PullToRefresh 组件和 List 组件展示通过网络获取的文章列表数据,并且点击其中每一项都可以跳转详情页面,使用到的系统方法是router.pushUrl。

3.网络请求

其中网络请求代码如下:

/*** 发起 HTTP GET 请求的函数* @param url 请求的 URL 地址* @param extraData 额外的请求数据,可选参数* @returns 返回 Promise 对象,包含 ResponseResult 数据*/
export function httpRequestGet(url: string, extraData?: Record<string, any>): Promise<ResponseResult> {// 创建 HTTP 请求实例let httpRequest = http.createHttp();// 发起 HTTP GET 请求let responseResult = httpRequest.request(url, {method: http.RequestMethod.GET,readTimeout: Constants.HTTP_READ_TIMEOUT,header: {'Content-Type': ContentType.JSON},connectTimeout: Constants.HTTP_READ_TIMEOUT,extraData: extraData || {}  // 使用 extraData 参数,如果不存在则传递一个空对象});// 创建用于存储响应数据的对象let serverData: ResponseResult = new ResponseResult();// 处理返回的数据并返回结果return responseResult.then((value: http.HttpResponse) => {// 检查 HTTP 响应码是否为成功状态(200)if (value.responseCode === Constants.HTTP_CODE_200) {// 解析返回的数据let result = `${value.result}`;let resultJson: ResponseResult = JSON.parse(result);// 检查服务器返回的错误码是否为成功状态if (resultJson.errorCode === Constants.SERVER_CODE_SUCCESS) {// 将返回的数据赋值给 serverData 对象serverData.data = resultJson.data;}// 将服务器返回的错误码和错误消息赋值给 serverData 对象serverData.errorCode = resultJson.errorCode;serverData.errorMsg = resultJson.errorMsg;} else {// 设置错误消息,包含 HTTP 错误码serverData.errorMsg = `${$r('app.string.http_error_message')}&${value.responseCode}`;}// 返回处理后的 serverData 对象return serverData;}).catch((err) => {// 捕获异常,打印错误信息,并设置错误消息console.log("error:" + JSON.stringify(err));serverData.errorMsg = $r('app.string.http_error_message');// 返回处理后的 serverData 对象return serverData;});
}
4.详情页面

详情页面是通过webview来展示网页实现的,代码如下:

// 标记为入口
@Entry
// 标记为组件
@Component
// Web 页面结构体
struct WebPage {// 从路由获取参数中的 'src',并存储到状态中@State src: string = router.getParams()?.['src'];// 从路由获取参数中的 'title',并存储到状态中@State title: string = router.getParams()?.['title'];// Web 页面控制器controller: web_webview.WebviewController = new web_webview.WebviewController();// 构建界面build() {// 使用 Column 组件创建垂直布局Column() {// 页面标题组件PageTitle({ titleName: this.title })// 分隔线Divider().strokeWidth('1px').color($r('sys.color.ohos_id_color_list_separator'))// Web 组件,加载指定的网址,并使用控制器进行交互Web({src: this.src, controller: this.controller}).javaScriptAccess(true)}}
}// 页面标题组件结构体
@Component
struct PageTitle {// 标题名称private titleName: string// 构建界面build() {// 使用 Row 组件创建水平布局Row() {// 返回按钮图标Image($r('app.media.back')).width(20).height(20).onClick(() => {// 点击返回按钮,触发路由返回操作router.back()})// 标题文本Text(this.titleName).fontSize(Constants.PAGE_TITLE_TEXT_SIZE).width(Constants.PAGE_TITLE_TEXT_WIDTH).maxLines(Constants.PAGE_TITLE_TEXT_MAX_LINES).textOverflow({ overflow: TextOverflow.Ellipsis }).margin({ left: 20 })}// 设置整体内边距.padding(12)// 设置整体宽度为100%.width('100%')}
}

四、源码地址

WanAndroid: 基于鸿蒙ArkTS语言实现的WanAndroid App

如果觉得本文不错的话,帮忙点个赞吧~感谢~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/623139.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FFmpeg解决视频播放加载卡顿问题(FFmpeg+M3U8分片)

FFmpeg解决视频播放加载卡顿问题(FFmpegM3U8分片) 在这静谧的时光里&#xff0c;我们能够更清晰地审视自己&#xff0c;思考未来的方向。每一步的坚实&#xff0c;都是对勇气的拥抱&#xff0c;每一个夜晚的努力&#xff0c;都是对未来的信仰。不要害怕独行&#xff0c;因为正是…

spring boot application yaml key下划线如何转java的Properties对象字段驼峰

spring boot yaml key和value如何映射到Properties对象 下面以MybatisPlusProperties为例 ##java properties 字段驼峰 ##yaml文件如图&#xff0c;key使用下划线 ##java对象驼峰转下划线匹配yaml文件key DataObjectPropertyName.toDashedForm(name);//驼峰转下划线 ##设置P…

开发er们必知的Git命令

Git和GitHub是每位软件工程师都必须了解的最基本的东西。这些工具是开发人员日常工作的组成部分,因为我们每天都要与它们进行交互。熟练掌握Git不仅能简化您的生活,还能显著提高生产力。在这篇博文中,我们将探索一组命令,这些命令将大大提高您的生产力。随着您对这些命令的掌握…

Codeforces Round 779 (Div. 2) D2. 388535(思维题 二进制性质/trie树上最大最小异或)

题目 t(t<1e5)组样例&#xff0c;每次给定l,r(0<l<r<2^17) 和r-l1个数ai&#xff0c;新序列是被[l,r]这些数异或上同一个x得到的&#xff0c; 求出x&#xff0c;有多个输出任意一个即可 思路来源 官方题解 洛谷题解 Educational Codeforces Round 157 (Rated…

Linux系统使用超详细(十)~vi/vim命令①

vi/vim命令有很多&#xff0c;其实只有少数的用法对于我们日常工作中起到了很大帮助&#xff0c;但是既然我选择梳理Linux的学习笔记&#xff0c;那么一定全力把自己的理解和学习笔记的内容认真整理汇总&#xff0c;内容或许有错误&#xff0c;还请发现的C友们发现了及时指出。…

CTFhub-phpinfo

CTFhub-Web-信息泄露-“phpinfo” 题目信息 解题过程 ctrlF搜索关键字…

探索数据之美:深入Seaborn的数据可视化艺术与技巧【第26篇—python:Seaborn】

文章目录 1. 引言2. Seaborn基础2.1 安装和环境设置2.2 常用数据可视化函数2.3 设置样式和颜色主题 3. 数据准备与导入3.1 使用Pandas库加载和处理数据3.2 数据清理和缺失值处理 4. Seaborn中的常见图表4.1 折线图和散点图&#xff1a;展示趋势和变量关系4.2 条形图和箱线图&am…

树莓派4B-Python-使用PCA9685控制舵机云台+跟随人脸转动

系列文章 树莓派4B-Python-控制舵机树莓派-Pico控制舵机树莓派4B-Python-使用PCA9685控制舵机云台跟随人脸转动&#xff08;本文章&#xff09; 目录 系列文章前言一、SG90s舵机是什么&#xff1f;二、PCA9685与舵机信号线的接线图三、控制SG90s云台&#xff08;也可用来测试舵…

MongoDB Compass 的教程

第一步&#xff1a;建立连接 点击Save&Connect 增加数据库&#xff1a; 填写数据库名字和文档名字并点击Create Database 删除文档&#xff1a; 创建文档&#xff1a; 插入文档数据 {Id:1001,name:"cyl",age:21} 插入成功&#xff1a; 更改原有数据 删除原有数据…

ACM论文LaTeX模板解析(二)| documentclass设置

本文收录于专栏&#xff1a;ACM 论文 LaTeX模板解析&#xff0c;本专栏将会围绕ACM 论文 LaTeX模板解析持续更新。欢迎点赞收藏关注&#xff01; 文章目录 要使用documentclass类&#xff0c;请在文件的开头中写明&#xff1a; \documentclass[⟨options⟩]{acmart}有几个选项…

SpringBoot-项目部署

SpringBoot项目部署可以通过将项目打成可执行的jar包或war包来实现&#xff0c;也可以使用容器化技术如Docker将项目部署到云平台中。在部署时需要注意配置文件的位置和启动参数的设置&#xff0c;同时确保目标环境中的Java版本与项目所需的Java版本一致。部署完成后&#xff0…

【Nuxt3】Nuxt3脚手架nuxi安装项目和项目目录介绍

简言 最近学了Nuxt3,并使用它创建了自己的小网站。记录下学习到的nuxt3内容。 Nuxt3官网 Nuxt 是一个免费的开源框架&#xff0c;可通过直观、可扩展的方式使用 Vue.js 创建类型安全、高性能、生产级的全栈 Web 应用程序和网站。 支持SSR、SPA、建立静态网站&#xff0c;也可以…

如何在BTC生态中创造独特的数字资产?bitget教程

BRC-20通证是什么&#xff1f; 听说了吗&#xff1f;BRC-20通证在比特币上搞事情啦&#xff01;它们不依赖智能合约&#xff0c;直接在比特币的最小单位上动手脚。这就像在用最小的积木搭房子&#xff0c;太神奇了&#xff01;虽然现在还在实验阶段&#xff0c;但已经有很多人…

12AOP面向切面编程/GoF之代理模式

先看一个例子&#xff1a; 声明一个接口&#xff1a; // - * / 运算的标准接口! public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j); }实现该接口&#xff1a; package com.sunsplanter.prox…

流星全自动网页生成系统重构版源码

流星全自动网页生成系统重构版源码分享&#xff0c;所有模板经过精心审核与修改&#xff0c;完美兼容小屏手机大屏手机&#xff0c;以及各种平板端、电脑端和360浏览器、谷歌浏览器、火狐浏览器等等各大浏览器显示。 为用户使用方便考虑&#xff0c;全自动网页制作系统无需繁琐…

错误处理(基于ESP-IDF)

主要参考资料 B站Up主孤独的二进制《错误处理 - 乐鑫 ESP32 物联网开发框架 ESP-IDF 开发入门》 ESP-IDF编程指南>API指南>错误消息: https://docs.espressif.com/projects/esp-idf/zh_CN/v5.1/esp32s3/api-guides/error-handling.html ESP-IDF编程指南>API指南>严…

二、QT下载、安装及问题解决(windows系统)

本章节最重要的一点&#xff1a;安装时&#xff0c;路径中不能有中文&#xff0c;切记&#xff0c;否则QT不能正常运行。 下载两种途径&#xff1a; 1、官网下载&#xff0c;慢且不好访问&#xff1b; 2、国内一些大学网站的镜像&#xff0c;下载比较快&#xff0c;但是可能…

Android中的anr定位指导与建议

1.背景 8月份安卓出现了一次直播间卡死(ANR)问题&#xff0c;且由于排查难度较大&#xff0c;持续了较长时间。本文针对如何快速定位安卓端出现ANR问题进行总结和探讨. 这里大致补充一下当时的情况,当时看到情景的是从某一个特定的场景下进入直播间后整个直播间界面立刻就卡住…

lenovo联想笔记本电脑拯救者Legion Y7000 2019 PG0(81T0)原装出厂Windows10系统

链接&#xff1a;https://pan.baidu.com/s/1fn0aStc4sfAfgyOKtMiCCA?pwdas1l 提取码&#xff1a;as1l 联想拯救者原厂Win10系统自带所有驱动、出厂主题壁纸、系统属性联机支持标志、系统属性专属LOGO标志、Office办公软件、联想电脑管家等预装程序 所需要工具&#xff1a;…

更换为mainwindow.ui更新工程架构

文章目录 前言一、新建带mainwindow.ui的工程1.新建工程2. 添加工程模块添加opencv的库3.添加资源3.1工程上添加资源3.2引用资源 4.添加曲线文件4.1 复制关键文件到新工程4.2 新进显示曲线的ui带.h的为了方面名字取一样4.3添加曲线显示控件4.4 添加工具 5. 添加曲线.h文件内容6…