纯血鸿蒙APP实战开发——阅读翻页方式案例
介绍
本示例展示手机阅读时左右翻页,上下翻页,覆盖翻页的功能。
效果图预览
使用说明
- 进入模块即是左右翻页模式。
- 点击屏幕中间区域弹出上下菜单。
- 点击设置按钮,弹出翻页方式切换按钮,点击可切换翻页方式。
- 左右翻页方式可点击翻页,也可滑动翻页,点击屏幕左边1/3区域向左翻页,点击中间1/3区域弹出菜单,点击屏幕右边1/3区域向右翻页。
- 上下翻页方式只可上下滑动翻页。
- 覆盖翻页方式可点击翻页,也可滑动翻页,点击屏幕左边1/3区域向左翻页,点击中间1/3区域弹出菜单,点击屏幕右边1/3区域向右翻页。
实现思路
本例涉及的关键特性和实现方案如下:
场景一: 左右翻页方式通过swiper
+lazyforeach
+cachecount
实现按需加载。
实现步骤:
- 在
aboutToAppear()
方法中通过pushItem
向后加载数据,addItem
向前加载数据。 - 使用
Swiper
组件和LazyForEach
将数据源中的每条数据存放于Text组件中,Swiper
向左或向右滑动的效果就是左右翻页的效果。 - 需要网络加载时可在
BasicDataSource
的getData
方法中进行。当index等于0向前申请网络数据,当index
等于this.totalCount() - 1时向后请求网络数据。 - 请求完数据后可通过
push
方法将数据插入到队尾,通过unshift
插入到队头,具体可参考BasicDataSource
的pushItem
和addItem
方法。
Swiper(this.swiperController) { /*** TODO: 高性能知识点: 使用了cachedCount设置预加载的Text的数量,只在LazyForEach中生效,设置该属性后会缓存cachedCount个Text,LazyForEach超出显示和缓存范围的Text会被释放。* 使用cachedCount参数的例子:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/ui-ts-performance-improvement-recommendation-0000001477981001-V2*/LazyForEach(this.data, (item: string) => {Text($r(item))...}, (item: string) => item)}// TODO:知识点:index设置当前在容器中显示的子组件的索引值。设置小于0或大于等于子组件数量时,按照默认值0处理。.index(this.currentPageNum - CONFIGURATION.PAGEFLIPPAGECOUNT).width($r('app.string.pageflip_full_size')).height($r('app.string.pageflip_full_size')).indicator(false).cachedCount(CONFIGURATION.PAGEFLIPCACHECOUNT)...
aboutToAppear(): void {/*** 请求网络数据之后可以通过this.data.addItem(new Item('app.string.content' + i.toString()));的方法插入到数据源的开头形成新的数据源。* 请求网络数据之后可以通过this.data.pushItem(new Item('app.string.content' + i.toString()));的方法插入到数据源的末尾形成新的数据源。*/for (let i = CONFIGURATION.PAGEFLIPPAGESTART; i <= CONFIGURATION.PAGEFLIPPAGEEND; i++) {this.data.pushItem(STRINGCONFIGURATION.PAGEFLIPRESOURCE + i.toString());}
}
public getData(index: number): string {/*** TODO:知识点:1.当index等于this.totalCount() - 1时向后请求网络数据。当index等于0时向前请求网络数据。* TODO:知识点:2.新请求到的数据可以通过push插入到队尾,通知listeners刷新添加可参考pushItem方法。如果想要插到队头可以通过unshift插入到队头,通知listeners刷新添加可参考addItem方法。*/return this.elements[index];
}
场景二: 上下翻页方式通过list
+lazyforeach
+cachecount
实现按需加载。
实现步骤:
- 在
aboutToAppear()
方法中通过pushItem
向后加载数据,addItem
向前加载数据。 - 使用
List
组件和LazyForEach
将数据源中的每条数据存放于Text组件中,List
向上或向下滑动的效果就是上下翻页的效果。 - 需要网络加载时可在
BasicDataSource
的getData
方法中进行。当index等于0向前申请网络数据,当index
等于this.totalCount() - 1时向后请求网络数据。 - 请求完数据后可通过
push
方法将数据插入到队尾,通过unshift
插入到队头,具体可参考BasicDataSource
的pushItem
和addItem
方法。
// TODO:知识点:initialIndex设置为负数或超过了当前List最后一个item的索引值时视为无效取值,无效取值按默认值0显示。
List({ initialIndex: this.currentPageNum - CONFIGURATION.PAGEFLIPPAGECOUNT }) {/*** TODO: 高性能知识点: 使用了cachedCount设置预加载的ListItem的数量,只在LazyForEach中生效,设置该属性后会缓存cachedCount个ListItem,LazyForEach超出显示和缓存范围的ListItem会被释放。* 使用cachedCount参数的例子:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/ui-ts-performance-improvement-recommendation-0000001477981001-V2*/LazyForEach(this.data, (item: string) => {ListItem() {Text($r(item))...}}, (item: string) => item)
}
.width($r('app.string.pageflip_bottomview_row_text_width'))
.height($r('app.string.pageflip_full_size'))
.scrollBar(BarState.Off)
.cachedCount(CONFIGURATION.PAGEFLIPCACHECOUNT)
.onScrollIndex((firstIndex: number) => {this.currentPageNum = firstIndex + CONFIGURATION.PAGEFLIPPAGECOUNT; // 通过onScrollIndex监听当前处于第几页。
})
aboutToAppear(): void {/*** 请求网络数据之后可以通过this.data.addItem(new Item('app.string.content' + i.toString()));的方法插入到数据源的开头形成新的数据源。* 请求网络数据之后可以通过this.data.pushItem(new Item('app.string.content' + i.toString()));的方法插入到数据源的末尾形成新的数据源。*/for (let i = CONFIGURATION.PAGEFLIPPAGESTART; i <= CONFIGURATION.PAGEFLIPPAGEEND; i++) {this.data.pushItem(STRINGCONFIGURATION.PAGEFLIPRESOURCE + i.toString());}
}
public getData(index: number): string {/*** TODO:知识点:1.当index等于this.totalCount() - 1时向后请求网络数据。当index等于0时向前请求网络数据。* TODO:知识点:2.新请求到的数据可以通过push插入到队尾,通知listeners刷新添加可参考pushItem方法。如果想要插到队头可以通过unshift插入到队头,通知listeners刷新添加可参考addItem方法。*/return this.elements[index];
}
场景三: 覆盖翻页方式通过三个Stack
组件通过滑动+动画+改变组件内容实现效果。
实现步骤:
- 在
Stack
组件中布局三个ReaderPage
,midPage
位于中间可以根据this.offsetX实时translate自己的位置。 - 当this.offsetX<0时,translate的x为this.offsetX,midPage向左移动,显现
rightPage
。 - 当this.offsetX>0,translate的x为0,midPage不动,
leftPage
向右滑动。 - 将滑动翻页的动画和点击翻页的动画封装在一个闭包中,由
isClick
来判断是点击翻页还是滑动翻页,由isLeft
来判断点击翻页中是向左翻页还是向右翻页。 - 确定翻页时将this.offsetX设置为this.screenW或者-this.screenW。translate移动加上动画效果就会产生覆盖翻页的效果。
- 最终滑动动画结束时this.offsetX都会被置为0,leftPage和midPage回归原位。
- 当动画结束时由于翻页会让
this.currentPageNum
加一或减一,根据相应的页数来加载三个content
相应的内容。
Stack() {ReaderPage({ content: this.rightPageContent }); // 当midPage向左滑时,rightPage开始显现。ReaderPage({ content: this.midPageContent })/** TODO: 知识点:* 当this.offsetX<0时,translate的x为this.offsetX,midPage向左移动,显现rightPage。* 当this.offsetX>0,translate的x为CONFIGURATION.PAGEFLIPZERO,midPage不动,leftPage向右滑动。*/.translate({x: this.offsetX >= CONFIGURATION.PAGEFLIPZERO ? CONFIGURATION.PAGEFLIPZERO : this.offsetX,y: CONFIGURATION.PAGEFLIPZERO,z: CONFIGURATION.PAGEFLIPZERO}).width(this.screenW);ReaderPage({ content: this.leftPageContent }) // TODO: 知识点:在midPage的左边,当向右滑时,跟随this.offsetX向右滑动。.translate({x: -this.screenW + this.offsetX});
}
private clickAnimateTo(isClick: boolean, isLeft?: boolean) {animateTo({duration: CONFIGURATION.PAGEFLIPTOASTDURATION,curve: Curve.EaseOut,onFinish: () => {/** TODO: 知识点:this.currentPageNum加一或者减一后修改组件的内容。* 右滑:1. 恢复页面原始状态 2. 修改组件的内容为 page1 = content1-1, page2 = content2-1,page3 = content3-1* 左滑:1. 恢复页面原始状态 2. 修改组件的内容为 page1 = content1+1, page2 = content2+1,page3 = content3+1*/if (this.offsetX > CONFIGURATION.PAGEFLIPRIGHTFLIPOFFSETX && this.currentPageNum !== CONFIGURATION.PAGEFLIPPAGESTART) {this.currentPageNum -= CONFIGURATION.PAGEFLIPPAGECOUNT;} else if (this.offsetX < CONFIGURATION.PAGEFLIPLEFTFLIPOFFSETX && this.currentPageNum !== CONFIGURATION.PAGEFLIPPAGEEND) {this.currentPageNum += CONFIGURATION.PAGEFLIPPAGECOUNT;}this.offsetX = CONFIGURATION.PAGEFLIPZERO;this.simulatePageContent();}}, () => {if (isClick) { // 是否为点击翻页if (isLeft) {this.offsetX = this.screenW; // TODO: 知识点:右滑距离变为一个屏幕宽度,ReaderPage就会向右移动一个屏幕宽度,加上动画,形成了覆盖翻页的效果。} else {this.offsetX = -this.screenW; // TODO: 知识点:左滑距离变为一个屏幕宽度,ReaderPage就会向左移动一个屏幕宽度,加上动画,形成了覆盖翻页的效果。}} else { // 滑动翻页if (this.offsetX > CONFIGURATION.PAGEFLIPRIGHTFLIPOFFSETX && this.currentPageNum !== CONFIGURATION.PAGEFLIPPAGESTART) {this.offsetX = this.screenW;} else if (this.offsetX < CONFIGURATION.PAGEFLIPLEFTFLIPOFFSETX && this.currentPageNum !== CONFIGURATION.PAGEFLIPPAGEEND) {this.offsetX = -this.screenW;} else {this.offsetX = CONFIGURATION.PAGEFLIPZERO; // 当位于第一页和末尾页,移动距离设为0,无法翻页。}}});
}
// 模拟书页内容,可以在此进行网络请求。
simulatePageContent() {this.leftPageContent = STRINGCONFIGURATION.PAGEFLIPRESOURCE + (this.currentPageNum - CONFIGURATION.PAGEFLIPPAGECOUNT).toString();this.midPageContent = STRINGCONFIGURATION.PAGEFLIPRESOURCE + (this.currentPageNum).toString();this.rightPageContent = STRINGCONFIGURATION.PAGEFLIPRESOURCE + (this.currentPageNum + CONFIGURATION.PAGEFLIPPAGECOUNT).toString();
}
工程结构&模块类型
pageflip // har包|---common| |---Constants.ets // 常量 |---components| |---mainpage | |---PageFlip.ets // 主页面|---datasource| |---BasicDataSource.ets // Basic数据控制器|---view| |---BottomView.ets // 底部菜单视图| |---CoverFlipPage.ets // 覆盖翻页视图| |---LeftRightFlipPage.ets // 左右翻页视图| |---TopView.ets // 顶部菜单视图| |---UpDownFlipPage.ets // 上下翻页视图
模块依赖
routermodule
高性能知识点
本例使用了onActionUpdate函数。该函数是系统高频回调函数,避免在函数中进行冗余或耗时操作,例如应该减少或避免在函数打印日志,会有较大的性能损耗。
本示例使用了LazyForEach进行数据懒加载,List布局时会根据可视区域按需创建ListItem组件,并在ListItem滑出可视区域外时销毁以降低内存占用。
本示例使用了cachedCount设置预加载的ListItem的数量,只在LazyForEach中生效,设置该属性后会缓存cachedCount个ListItem,LazyForEach超出显示和缓存范围的ListItem会被释放。
参考资料
LazyForEach:数据懒加载
ZIndex
List
Swiper
@Link装饰器:父子双向同步
鸿蒙全栈开发全新学习指南
也为了积极培养鸿蒙生态人才,让大家都能学习到鸿蒙开发最新的技术,针对一些在职人员、0基础小白、应届生/计算机专业、鸿蒙爱好者等人群,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线【包含了大厂APP实战项目开发】。
本路线共分为四个阶段:
第一阶段:鸿蒙初中级开发必备技能
第二阶段:鸿蒙南北双向高工技能基础:gitee.com/MNxiaona/733GH
第三阶段:应用开发中高级就业技术
第四阶段:全网首发-工业级南向设备开发就业技术:https://gitee.com/MNxiaona/733GH
《鸿蒙 (Harmony OS)开发学习手册》(共计892页)
如何快速入门?
1.基本概念
2.构建第一个ArkTS应用
3.……
开发基础知识:gitee.com/MNxiaona/733GH
1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……
基于ArkTS 开发
1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……
鸿蒙开发面试真题(含参考答案):gitee.com/MNxiaona/733GH
鸿蒙入门教学视频:
美团APP实战开发教学:gitee.com/MNxiaona/733GH
写在最后
- 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
- 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
- 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
- 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:
gitee.com/MNxiaona/733GH
相关文章:

纯血鸿蒙APP实战开发——阅读翻页方式案例
介绍 本示例展示手机阅读时左右翻页,上下翻页,覆盖翻页的功能。 效果图预览 使用说明 进入模块即是左右翻页模式。点击屏幕中间区域弹出上下菜单。点击设置按钮,弹出翻页方式切换按钮,点击可切换翻页方式。左右翻页方式可点击翻…...

如何从Mac电脑恢复任何删除的视频
Microsoft Office是包括Mac用户在内的人们在世界各地创建文档时使用的最佳软件之一。该软件允许您创建任何类型的文件,如演示文稿、帐户文件和书面文件。您可以使用 MS Office 来完成。所有Microsoft文档都可以在Mac上使用。大多数情况下,您处理文档&…...
【Halcon 内存泄漏记录 - C#】
Halcon 内存泄漏记录 - C# 1. Bitmap 转 HImage2. new 之后要Dispose()3. 切换配方后,内存会增加4. Parallel.For 嵌套Parallel.For, 会出现问题5. 图像预处理使用需要注意不能直接在原有变量上赋值 1. Bitmap 转 HImage 由于Bitmap 在转化时使用Bitmap…...

MT8370_联发科MTK8370(Genio 510)芯片性能规格参数
MT8370芯片是一款利用超高效的6nm制程工艺打造的边缘AI平台,具有强大的性能和功能。这款芯片集成了六核CPU(2x2.2 GHz Arm Cortex-A78 & 4x2.0 GHz Arm Cortex-A55)、Arm Mali-G57 MC2 GPU、集成的APU(AI处理器)和DSP,以及一个HEVC编码加速引擎&…...

【Qt 学习笔记】Qt常用控件 | 多元素控件 | Table Widget的说明及介绍
博客主页:Duck Bro 博客主页系列专栏:Qt 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ Qt常用控件 | 多元素控件 | Table Widget的说明及介绍 文章编号&#…...

ES全文检索支持拼音和繁简检索
ES全文检索支持拼音和繁简检索 1. 实现目标2. 引入pinyin插件2.1 编译 elasticsearch-analysis-pinyin 插件2.2 安装拼音插件 3. 引入ik分词器插件3.1 已有作者编译后的包文件3.2 只有源代码的版本3.3 安装ik分词插件 4. 建立es索引5.测试检索6. 繁简转换 1. 实现目标 ES检索时…...

【DDR 终端稳压器】Sink and Source DDR Termination Regulator [C] S0 S1 S2 S3 S4 S5 6状态
TPS51200A-Q1 器件通过 EN 功能提供 S3 支持。EN引脚可以连接到终端应用中的SLP_S3信号。当EN 高电平(S0 状态)时,REFOUT 和 VO 引脚均导通。当EN 低电平(S3状态)时,VO引脚关断并通过内部放电MOSFET放电时…...

使用IIS部署Vue项目
前提 使用IIS部署Vue项目,后端必须跨域,不要在Vue中用proxy跨域,那个只在dev环境中有用! IIS安装,不用全部打勾,有些他默认就是方块 ■ 选择性安装的,就维持原样就可以。 添加网站配置 右键…...

QT+多线程TCP服务器+进阶版
针对之前的服务器,如果子线程工作类里面需要使用socket发送消息,必须要使用信号与槽的方法, 先发送一个信号给父进程,父进程调用socket发送消息(原因是QT防止父子进程抢夺同一资源,因此直接规定父子进程不能…...

Java入门基础学习笔记12——变量详解
变量详解: 变量里的数据在计算机中的存储原理。 二进制: 只有0和1, 按照逢2进1的方式表示数据。 十进制转二进制的算法: 除二取余法。 6是110 13是1101 计算机中表示数据的最小单元:一个字节(byte&…...

bitmap requires a valid src attribute
关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 ,擅长java后端、移动开发、商业变现、人工智能等,希望大家多多支持。 未经允许不得转载 目录 一、导读二、概览三、问题记录四、 推…...

Java刷题-基础篇
目录 题目1:打印1~100内奇数和、偶数和 题目2:计算5的阶乘 题目3:计算 1!2!3!4!5! 的和 题目4:找1~100之间即能被3整除,又能被5整除的数字,要求必须使用break/continue 题目5:实现猜数字小…...

Linux——mysql运维篇
回顾基本语句: 数据定义语言 ( DDL ) 。这类语言用于定义和修改数据库的结构,包括创建、删除和修改数据库、表、视图和索引等对象。主要的语句关键字包括 CREATE 、 DROP 、 ALTER 、 RENAME 、 TRUNCATE 等。 create database 数据库 &…...

力扣每日一题-统计已测试设备-2024.5.10
力扣题目:统计已测试设备 题目链接: 2960.统计已测试设备 题目描述 代码思路 根据题目内容,第一感是根据题目模拟整个过程,在每一步中修改所有设备的电量百分比。但稍加思索,发现可以利用已测试设备的数量作为需要减少的设备电…...

代码+视频,R言语处理数据中的缺失值
在SCI论文中,我们不可避免和缺失数据打交道,特别是在回顾性研究,对于缺失的协变量(就是混杂因素),我们可以使用插补补齐数据,但是对于结局变量和原因变量的缺失,我们不能这么做。部分…...
PGSync安装使用教程(PostgreSQL数据实时同步至Elasticsearch)
说明 pgsync项目有两个,一个是ankane/pgsync,用于pgsql之间的数据同步,另一个是toluaina/pgsync,用于pgsql的数据同步至es,本教程适用于第二个项目。 pgsync应该是目前为止唯二支持es8的数据同步工具,另一…...
前端主题切换的多种方式
动态link标签加载不同主题css **原理:**提前准备好几套CSS主题样式文件,在点击切换主题时,创建link标签动态加载到head标签中,或者是动态改变link标签的href属性。 缺点: 动态加载样式文件,如果文件过大网…...
使用RESTful API构建 web 应用程序
RESTful API是一种基于HTTP协议的架构风格,用于设计网络应用程序的 API。它强调使用标准的HTTP方法(如GET、POST、PUT和DELETE)对资源进行操作,并使用统一的资源标识符(URI)来唯一标识每个资源。RESTful AP…...
KaiOS Data PDN 数据建立流程
代码逻辑 APN创建 在 DataCallManager.jsm中,会对所有apnsetting创建一个datacall,其中会包含dataprofile的成员(通过apn参数来创建),在之后的流程用于直接发送到modem建立PDN。 PDN建立 1、DataCallManager.jsm -dcInterface.setupDataCall //RILNetworkInterface.c…...

Mybatis-Plus常用的增删改查坑
添加依赖 <!--实体类上加上Data注解就不用写get,set,toString,equals等方法了--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional…...
大模型的LoRa通讯详解与实现教程
一、LoRa通讯技术概述 LoRa(Long Range)是一种低功耗广域网(LPWAN)通信技术,由Semtech公司开发,特别适合于物联网设备的长距离、低功耗通信需求。LoRa技术基于扩频调制技术,能够在保持低功耗的同时实现数公里甚至数十公里的通信距离。 LoRa的主要特点 长距离通信:在城…...

【立体匹配】:双目立体匹配SGBM:(1)运行
注:这是一个专题,我会一步步介绍SGBM的实现,按照我的使用和优化过程逐步改善算法,附带实现方法 系列文章【立体匹配】:双目立体匹配SGBM:(1)运行 【立体匹配】:双目立体匹…...
【AI大模型】Transformer架构到底是什么?
引言 —— 想象一台能瞬间读懂整本《战争与和平》、精准翻译俳句中的禅意、甚至为你的设计草图生成前端代码的机器——这一切并非科幻,而是过去七年AI领域最震撼的技术革命:Transformer架构创造的奇迹。 当谷歌在2017年揭开Transformer的神秘面纱时&…...

机器学习——随机森林算法
随机森林算法是一种强大的树集成算法,比使用单个决策树效果要好得多。 以下是生成树集成的方法:假设有一个大小为m的训练集,然后对于b1到B,所以执行B次,可以使用有放回抽样来创建一个大小为m的训练集。所以如果有10个…...
SpringBoot3中使用虚拟线程的详细过程
在 Spring Boot 3 中使用 Java 21 的虚拟线程(Virtual Threads)可以显著提升 I/O 密集型应用的并发能力。以下是详细实现步骤: 1. 环境准备 JDK 21:确保安装 JDK 21 或更高版本Spring Boot 3.2:最低要求(p…...
添加按钮跳转页面并且根据网站的用户状态判断是否显示按钮
现在我们需要的是为页面添加一个按钮,这个按钮是动态的,需要根据网站用户登录过后是否是vip来判断是否显示,然后按钮的效果是跳转到某个页面。 首先我们需要在页面中找到我们需要添加按钮的位置,找到对应的文件,然后比…...

【五子棋在线对战】三.数据管理模块实现
数据管理模块实现 1.数据库表的设计2.数据管理模块的封装和实现2.1 user_table() && ~user_table()2.2 insert() 注册时新增用户2.3 login() 登录验证,并返回详细的用户信息2.4 通过用户名获取用户信息 && 通过用户id获取用户信息2.5 win() &&a…...

php apache构建 Web 服务器
虚拟机配置流程winsever2016配置Apache、Mysql、php_windows server 2016配置web服务器-CSDN博客 PHP 和 Apache 通过 模块化协作 共同构建 Web 服务器,以下是它们的交互机制和工作流程: 一、核心组件分工 组件角色ApacheWeb …...

直角坐标系和斜角坐标系
前情概要 笛卡尔坐标系是直角坐标系和斜角坐标系的统称。为什么会有这两种坐标系呢,教材中为什么最后只用直角坐标系呢?我们这样解释: 研究一维空间中的向量时,由于一维空间中的向量有无数条,如果我们选定一条作为基…...
PostgreSQL 的扩展pg_prewarm
PostgreSQL 的扩展pg_prewarm pg_prewarm 是 PostgreSQL 提供的一个实用扩展,用于将数据预先加载到共享缓冲区或操作系统缓存中,从而提升查询性能。 一、扩展概述 核心功能 手动预热:将指定的表或索引数据加载到内存自动预热:…...