HarmonyOS NEXT 应用开发实战(七、知乎日报轮播图的完整实现)

在今天的博文中,我们将深入探讨如何在 HarmonyOS NEXT 中使用 ArkUI 实现一个轮播图组件。我们将通过一个示例代码来演示这个完整的过程,其中包含获取数据、管理数据源以及渲染组件等多个部分。 

 先来看下最终实现效果:

项目准备

首先,我们需要导入一些必要的模块和API,如下所示:

import { getSwiperList } from "../../common/api/home";
import { getZhiHuNews } from '../../common/api/zhihu';
import { BaseResponse, ErrorResp, ZhiNewsItem } from '../../common/bean/ApiTypes';
import { Log } from '../../utils/logutil';
import { formatDate } from '../../utils/time';

在这些模块中,getSwiperList 和 getZhiHuNews 是用于获取轮播图和知乎新闻数据的API。

api接口的定义十分简洁,实现如下:

import { setRequestConfig } from '../../utils/http';
import { BaseResponse,ZhiNewsRespData,ZhiDetailRespData } from '../bean/ApiTypes';// 调用setRequestConfig函数进行请求配置
setRequestConfig();const http = globalThis.$http;// 获取知乎列表页api接口
export const getZhiHuNews = (date:string): Promise<BaseResponse<ZhiNewsRespData>> => http.get('/zhihunews/'+date);// 获取知乎详情页api接口
export const getZhiHuDetail = (id:string): Promise<BaseResponse<ZhiDetailRespData>> => http.get('/zhihudetail/'+id);

api接口如何做到如此简洁的?这里推荐博主开源的官方http网络库封装:

HarmonyOS NEXT应用开发实战(二、封装比UniApp和小程序更简单好用的网络库)_鸿蒙网络库-CSDN博客 

数据源管理

这部分才是重点!在轮播图组件中,我们需要管理数据源。这部分使用了懒加载LazyForEach。该方法需要我们先定义加载数据源,我们首先编写一个泛型的公共数据源类,该类需要实现IDataSource接口,并重写totalCount、getData等方法。在这里,我们定义了两个数据源类:BasicDataSource 和 SwiperDataSource。这两个类可以帮助我们管理数据的监听和更新。

代码如下所示:

class BasicDataSource<T> implements IDataSource {// 监听器和数据数组private listeners: DataChangeListener[] = [];private originDataArray: T[] = [];totalCount(): number {return this.originDataArray.length;}getData(index: number): T {return this.originDataArray[index];}registerDataChangeListener(listener: DataChangeListener): void {// 注册数据变化监听器}unregisterDataChangeListener(listener: DataChangeListener): void {// 反注册数据变化监听器}// 通知重新加载数据notifyDataReload() { /* ... */ }// 通知添加数据notifyDataAdd(index: number) { /* ... */ }
}class SwiperDataSource<T> extends BasicDataSource<T> {private dataArray: T[] = [];totalCount(): number {return this.dataArray.length;}getData(index: number): T {return this.dataArray[index];}pushData(data: T): void {this.dataArray.push(data);this.notifyDataAdd(this.dataArray.length - 1);}reloadData(): void {this.dataArray = [];this.notifyDataReload();}
}

组件实现

接下来是主组件的实现,在 ZhiHu 类中,我们使用 Swiper 组件来创建轮播图。

@Component
export default struct ZhiHu {// 状态管理@State message: string = 'Hello World';private swiperController: SwiperController = new SwiperController();private swiperData: SwiperDataSource<ZhiNewsItem> = new SwiperDataSource();@State zhiNews: ZhiNewsItem[] = [];private currentDate = '';// 组件生命周期aboutToAppear() {getSwiperList().then((res) => {// 处理响应数据}).catch((err: BaseResponse<ErrorResp>) => {// 错误处理});getZhiHuNews(this.currentDate).then((res) => {this.zhiNews = res.data.stories;for (const itm of res.data.top_stories) {this.swiperData.pushData(itm);}}).catch((err: BaseResponse<ErrorResp>) => {// 错误处理});}build() {Navigation(this.pageStack) {Row() {Column({ space: 0 }) {// 标题栏Text("日报").size({ width: '100%', height: 50 }).backgroundColor("#28bff1").fontColor("#ffffff").textAlign(TextAlign.Center).fontSize("18fp");// 轮播图组件Swiper(this.swiperController) {LazyForEach(this.swiperData, (item: ZhiNewsItem) => {Stack({ alignContent: Alignment.Center }) {Image(item.image).width('100%').height(180).backgroundColor(0xAFEEEE).onClick(() => {this.pageStack.pushDestinationByName("PageOne", { id: item.id });});Text(item.title).padding(5).margin({ top: 60 }).width('100%').height(50).textAlign(TextAlign.Center).maxLines(2).textOverflow({ overflow: TextOverflow.Clip });}}, (item: ZhiNewsItem) => item.id).autoPlay(true).interval(4000).loop(true);}}}}.mode(NavigationMode.Stack).width('100%').height('100%');}
}

完整代码 

import {getSwiperList,getHotMovie} from "../../common/api/home"
import { getZhiHuNews } from '../../common/api/zhihu';
import { BaseResponse,ErrorResp,ZhiNewsItem } from '../../common/bean/ApiTypes';
import { Log } from '../../utils/logutil'
import { formatDate } from '../../utils/time';class BasicDataSource<T> implements IDataSource {private listeners: DataChangeListener[] = [];private originDataArray: T[] = [];totalCount(): number {return this.originDataArray.length;}getData(index: number): T {return this.originDataArray[index];}registerDataChangeListener(listener: DataChangeListener): void {if (this.listeners.indexOf(listener) < 0) {this.listeners.push(listener);}}unregisterDataChangeListener(listener: DataChangeListener): void {const pos = this.listeners.indexOf(listener);if (pos >= 0) {this.listeners.slice(pos, 1);}}// 通知LazyForEach组件需要重新重载所有子组件notifyDataReload(): void {this.listeners.forEach(listener => {listener.onDataReloaded();})}// 通知LazyForEach组件需要在index对应索引处添加子组件notifyDataAdd(index: number): void {this.listeners.forEach(listener => {listener.onDataAdd(index);})}
}class SwiperDataSource<T> extends BasicDataSource<T> {private dataArray: T[] = [];totalCount(): number {return this.dataArray.length;}getData(index: number): T {return this.dataArray[index];}// 在列表末尾添加数据并通知监听器pushData(data: T): void {this.dataArray.push(data);this.notifyDataAdd(this.dataArray.length - 1);}// 重载数据reloadData(): void {// 不会引起状态变化this.dataArray = [];// 必须通过DataChangeListener来更新this.notifyDataReload();}
}@Component
export default struct ZhiHu{@State message: string = 'Hello World';private swiperController: SwiperController = new SwiperController()private swiperData: SwiperDataSource<ZhiNewsItem> = new SwiperDataSource()@State zhiNews:ZhiNewsItem[] = []private currentDate= '' // 初始化为今天的日期private previousDate= '' // 上一天的日期pageStack: NavPathStack = new NavPathStack()// 组件生命周期aboutToAppear() {Log.info('ZhiHu aboutToAppear');this.currentDate = formatDate(new Date())getSwiperList().then((res) => {Log.debug(res.data.message)Log.debug("request","res.data.code:%{public}d",res.data.code)Log.debug("request","res.data.data[0]:%{public}s",res.data.data[0].id)Log.debug("request","res.data.data[0]:%{public}s",res.data.data[0].imageUrl)Log.debug("request","res.data.data[0]:%{public}s",res.data.data[0].title)}).catch((err:BaseResponse<ErrorResp>) => {Log.debug("request","err.data.code:%d",err.data.code)Log.debug("request",err.data.message)});//获取知乎新闻列表getZhiHuNews(this.currentDate).then((res) => {Log.debug(res.data.message)Log.debug("request","res.data.code:%{public}d",res.data.code)this.zhiNews = res.data.storiesfor (const itm of res.data.top_stories) {this.swiperData.pushData(itm)}}).catch((err:BaseResponse<ErrorResp>) => {Log.debug("request","err.data.code:%d",err.data.code)Log.debug("request",err.data.message)});}// 组件生命周期aboutToDisappear() {Log.info('ZhiHu aboutToDisappear');}build() {Navigation(this.pageStack){Row() {Column({ space: 0 }) {// 标题栏Text("日报").size({ width: '100%', height: 50 }).backgroundColor("#28bff1").fontColor("#ffffff").textAlign(TextAlign.Center).fontSize("18fp")// 内容项Swiper(this.swiperController) {LazyForEach(this.swiperData, (item: ZhiNewsItem) => {Stack({ alignContent: Alignment.Center }) {Image(item.image).width('100%').height(180).backgroundColor(0xAFEEEE).zIndex(1).onClick(() => {//this.pageStack.pushPathByName("PageOne", item)this.pageStack.pushDestinationByName("PageOne", { id:"9773231" }).catch((e:Error)=>{// 跳转失败,会返回错误码及错误信息console.log(`catch exception: ${JSON.stringify(e)}`)}).then(()=>{// 跳转成功});})// 显示轮播图标题Text(item.title).padding(5).margin({ top:60 }).width('100%').height(50).textAlign(TextAlign.Center).maxLines(2).textOverflow({overflow:TextOverflow.Clip}).fontSize(20).fontColor(Color.White).opacity(100) // 设置标题的透明度 不透明度设为100%,表示完全不透明.backgroundColor('#808080AA') // 背景颜色设为透明.zIndex(2)}}, (item: ZhiNewsItem) => item.id)}.cachedCount(2).index(1).autoPlay(true).interval(4000).loop(true).indicatorInteractive(true).duration(1000).itemSpace(0).curve(Curve.Linear).onChange((index: number) => {console.info(index.toString())}).onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) => {console.info("index: " + index)console.info("current offset: " + extraInfo.currentOffset)}).height(180) // 设置高度List({ space: 12 }) {ForEach(this.zhiNews, (item:ZhiNewsItem) => {ListItem() {Column({ space: 0 }) {Row() {Column({ space: 15 }) {Text(item.title).fontSize(16).fontWeight(FontWeight.Bold).align(Alignment.Start).width('100%')Text(item.hint).align(Alignment.Start).width('100%')}.justifyContent(FlexAlign.Start).width('70%').padding(5)Image(item.image).objectFit(ImageFit.Cover).borderRadius(5).height(100).padding(2)}.size({ width: '100%', height: 100 })Divider().strokeWidth(2).color('#F1F3F5')}.size({ width: '100%', height: 100 })}}, (itm:ZhiNewsItem) => itm.id)}.size({ width: '100%', height: '100%' })}.size({ width: '100%', height: '100%' })}}.mode(NavigationMode.Stack).width('100%').height('100%')}
}

项目开源地址

zhihudaily: HarmonyOS NEXT 项目开发实战,仿知乎日报的实现 

写在最后

最后,推荐下笔者的业余开源app影视项目“爱影家”,推荐分享给与我一样喜欢免费观影的朋友。【注:该项目仅限于学习研究使用!请勿用于其他用途!】

开源地址:爱影家app开源项目介绍及源码

https://gitee.com/yyz116/imovie

 其他资源

滑块视图容器

文档中心

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

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

相关文章

Deep Learning

深度学习 文章目录 前言面向开发人员的 NVIDIA AI 平台每个 AI 框架 - 加速统一平台从开发到部署前言 深度学习是 AI 和机器学习的一个子集,它使用多层人工神经网络在对象检测、语音识别、语言翻译等任务中提供最先进的准确性。 深度学习与传统机器学习技术的不同之处在于,深…

MySQL8.0主从同步报ERROR 13121错误解决方法

由于平台虚拟机宿主机迁移&#xff0c;导致一套MySQL主从库从节点故障&#xff0c;从节点服务终止&#xff0c;在服务启动后&#xff0c;恢复从节点同步服务&#xff0c;发现了如下报错&#xff1a; mysql> show slave status\G; *************************** 1. row *****…

Linux 外设驱动 应用 2 KEY 按键实验

2 按键 2.1 按键介绍 按键是指轻触式按键开关&#xff0c;也称之为轻触开关。按键开关是一种电子开关&#xff0c;属于电子元器件类&#xff0c;最早出现在日本&#xff0c;称之为&#xff1a;敏感型开关&#xff0c;使用时以满足操作力的条件向开关操作方向施压开关功能闭合…

spring05

一: 场景设定和问题复现 1 准备项目 pom.xml //单元测试:每个业务单独运行 <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.3.1</version> <scope>…

民宿预订新纪元:SpringBoot实现的在线平台

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理民宿在线预定平台的相关信息成为必然。开发…

springboot041师生健康信息管理系统(论文+源码)_kaic

摘 要 随着移动应用技术的发展&#xff0c;越来越多的用户借助于移动手机、电脑完成生活中的事务&#xff0c;许多的传统行业也更加重视与互联网的结合。 本论文主要介绍基于java的师生健康信息管理系统&#xff0c;运用软件工程原理和开发方法&#xff0c;采用springboot框架…

Flink时间语义和时间窗口

前言 在实际的流计算业务场景中&#xff0c;我们会发现&#xff0c;数据和数据的计算往往都和时间具有相关性。 举几个例子&#xff1a; 直播间右上角通常会显示观看直播的人数&#xff0c;并且这个数字每隔一段时间就会更新一次&#xff0c;比如10秒。电商平台的商品列表&a…

VSCode自搭建嵌入式环境的make构建工具选择

make构建工具即make.exe。 make.exe作为环境变量&#xff0c;和Makefile脚本同步协作&#xff0c;Makefile里面的语法规定了代码项目中多文件的编译顺序和编译规则。 ①MinGW-64&#xff1a;如果选择MinGW/bin文件目录下的mingw32-make.exe&#xff0c;将其重命名为make.exe&a…

2.cpp输入输出

cpp输入输出 1.cpp输入输出 1.cpp输入输出 项目中需要用到中文提示&#xff0c;需要去设置中更改字符编码为GBK&#xff0c;不然程序会乱码 注意&#xff1a;先设置编码格式&#xff0c;再创建工程 C 中的输入和输出&#xff08;I/O&#xff09;主要是通过标准库中的输入输出…

scala 抽象类

理解抽象类 抽象的定义 定义一个抽象类 &#xff1a;abstract class A {} idea实例 抽象类重写 idea实例 练习 1.abstract2.错3.abstract class A{}4.对

GROUP BY分组

1. 插入测试数据 INSERT INTO course (course_name,teacher_id) VALUES (毛概,1)&#xff0c; (线性代数,2)&#xff0c; (政治&#xff0c;3)&#xff0c; (程序设计语言,1)&#xff0c; (离散数学,2)&#xff0c; (编译技术,3)&#xff0c; (嵌入式基础,1)&#xff0c; (单片…

element plus中menu菜单技巧

我在使用element plus的menu&#xff08;侧边栏&#xff09;组件的过程中遇到了一些问题&#xff0c;就是menu编写样式和路由跳转&#xff0c;下面给大家分享以下&#xff0c;我是怎么解决的。 1.页面效果 我要实现的网站布局是这样的&#xff1a; 侧边栏折叠以后的效果&#…

C++数据结构-红黑树全面解读(进阶篇)

1.红黑树的概念 红黑树是一种二叉搜索树&#xff0c;但在每个结点上增加了一个存储位用于表示结点的颜色&#xff0c;这个颜色可以是红色的&#xff0c;也可以是黑色的&#xff0c;因此我们称之为红黑树。 红黑树通过对任何一条从根到叶子的路径上各个结点着色方式的限制&…

el-table表格里面有一条横线

表格里面 有一条横线&#xff0c; 出现原因&#xff1a;是自定义了表格头.使用了固定列&#xff08;fixed&#xff09;&#xff0c;定宽。就很难受。。。 添加样式文件&#xff1a; <style lang"scss" scoped>::v-deep {.el-table__fixed-right {height: 100%…

【STL】string类的使用

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;C、STL 目录 string类的介绍--为什么学习string类 一、string类的默认成员函数 构造函数(constructor) 析构函数(destructor) 赋值运算符重载operator 二…

java maven

参考链接 maven相关配置 maven依赖管理 依赖具有传递性。 maven依赖范围 maven的生命周期 分为三个相互独立的生命周期&#xff1a; 在执行对应生命周期的操作时&#xff0c;需要进行前面的操作。比如&#xff0c;执行打包install的时候&#xff0c;会执行test。

嵌入式入门学习——8基于Protues仿真Arduino+SSD1306液晶显示数字时钟

0 系列文章入口 嵌入式入门学习——0快速入门&#xff0c;Let‘s Do It&#xff01; SSD1306 1 Protues查找SSD1306器件并放置在画布&#xff0c;画好电气连接&#xff08;这里VCC和GND画反了&#xff0c;后面仿真出错我才看见&#xff0c;要是现实硬件估计就烧毁了&#xf…

抖音快手提取COOKIE双参软件-修行者编程技术网

抖音快手提取COOKIE双参软件-修行者编程技术网 我们在软件开发的过程中首先要知道&#xff0c;什么是ck&#xff0c;什么是双参数 为什么会有ck&#xff0c;ck是否存在算法在其中 UI代码工程展示

【火山引擎】调用火山大模型的方法 | SDK安装 | 配置 | 客户端初始化 | 设置

豆包 (Doubao) 是字节跳动研发的大规模预训练语言模型。 目录 1 安装 2 配置访问凭证 3 客户端初始化 4 设置地域和访问域名 5 设置超时/重试次数 1 安装 通过pip安装PYTHON SDK。 pip install volcengine-python-sdk[ark] 2 配置访问凭证 获取 API Key 访问凭证具体步…

【NOIP提高组】一元三次方程求解

【NOIP提高组】一元三次方程求解 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 有形如&#xff1a;ax3bx2cxd0 这样的一个一元三次方程。给出该方程中各项的系数(a&#xff0c;b&#xff0c;c&#xff0c;d均为实数)&#xff0c;并约定该方…