当前位置: 首页 > news >正文

【HarmonyOS】分页滚动文本组件

【HarmonyOS】实现分页滚动文本组件:为何选择 Scroll + Text 而非 textOverflow

import { promptAction } from '@kit.ArkUI'@Entry
@Component
struct Page37 {@State lineHeight: number = 0 // 单行文本的高度@State pageHeight: number = 0 // 每页的最大高度@State totalContentHeight: number = 0 // 整个文本内容的高度@State textContent: string = " " // 文本内容,默认一个空格是为了计算单行文本的高度@State scrollOffset: number = 0 // 当前滚动偏移量@State totalPages: number = 1 // 总页数@State currentPage: number = 1 // 当前页数scroller: Scroller = new Scroller() // 滚动条实例resetMaxLineHeight() {if (this.lineHeight > 0 && this.pageHeight > 0 && this.totalContentHeight > 0) {this.pageHeight = (Math.floor(this.pageHeight / this.lineHeight)) * this.lineHeightthis.totalPages = Math.ceil(this.totalContentHeight / this.pageHeight) //向上取整得到总页数}}build() {Column() {Text('第一章').margin({ top: 10, bottom: 10 }).backgroundColor(Color.Pink).width('100%').textAlign(TextAlign.Center)Column() {Scroll(this.scroller) {Column() {Text(this.textContent).backgroundColor(Color.Orange).fontSize(20).lineHeight(40).fontColor(Color.Black)// .textOverflow({ overflow: TextOverflow.Clip }).margin({ top: this.scrollOffset }).onAreaChange((oldArea: Area, newArea: Area) => {if (this.lineHeight == 0 && newArea.height > 0) {this.lineHeight = newArea.height as numberthis.resetMaxLineHeight()//添加数据测试let str = ""for (let i = 1; i <= 20; i++) {str += ` ${i}、荣誉和耻辱,是荣辱观中的一对基本范畴,是指社会对人们行为褒贬评价以及人们对这种评价的自我感受。知荣辱,是人性的标志,是人区别于动物、人之为人的重要标准。`}this.textContent = strreturn}if (this.totalContentHeight != newArea.height) {console.info(`newArea.height:${newArea.height}`)this.totalContentHeight = newArea.height as numberthis.resetMaxLineHeight()}})}.hitTestBehavior(HitTestMode.Block) //禁止滑动}.scrollBar(BarState.Off).constraintSize({ maxHeight: this.pageHeight == 0 ? 1000 : this.pageHeight })}.width('100%').layoutWeight(1).onAreaChange((oldArea: Area, newArea: Area) => {if (this.pageHeight == 0 && newArea.height > 0) {this.pageHeight = newArea.height as numberthis.resetMaxLineHeight()}})Row() {Button('上一页').onClick(() => {if (this.currentPage == 1) {promptAction.showToast({ message: "没有上一页了" })return;}this.scrollOffset += this.pageHeightthis.currentPage--;})Text(`${this.currentPage}/${this.totalPages}`)Button('下一页').onClick(() => {if (this.currentPage == this.totalPages) {promptAction.showToast({ message: "没有下一页了" })return;}this.scrollOffset -= this.pageHeightthis.currentPage++;})}.margin({ top: 10, bottom: 10 }).backgroundColor(Color.Pink).width('100%').justifyContent(FlexAlign.SpaceAround)}.width('100%').height('100%').backgroundColor(Color.Gray)}
}

【实现思路】

目标是实现在HarmonyOS应用中的分页滚动文本效果,使得用户能够通过“上一页”和“下一页”按钮来浏览不同的页面。我们选择使用 Scroll 组件结合 Text 组件来实现这一功能,而不是采用 textOverflow 的方式,原因在于 textOverflow 无法直接获取到文本控件被截断后的内容。

具体实现过程如下:

1. 初始化状态:

利用 @State 装饰器定义状态变量来存储单行文本的高度 (lineHeight)、每页的最大高度 (pageHeight)、文本内容的总高度 (totalContentHeight)、文本内容 (textContent)、滚动偏移量 (scrollOffset)、总页数 (totalPages) 和当前页数 (currentPage)。

2. 计算单行高度:

通过监听 Text 组件的 onAreaChange 事件,当首次获取到文本元素的高度时,将其赋值给 lineHeight 并调用 resetMaxLineHeight 方法来计算每页的最大高度。

3. 生成内容:

初始时,textContent 中包含一个空格,以便能够计算出单行文本的高度。一旦单行高度计算完成,通过循环生成多个段落填充文本内容。

4. 分页逻辑:

① 当 totalContentHeight 发生变化时,调用 resetMaxLineHeight 方法更新总页数。

② “上一页”和“下一页”按钮通过修改 scrollOffset 和 currentPage 来实现翻页效果。

5. UI 布局与滚动控制:

① 使用 Column 和 Row 布局来组织界面元素。

② Scroll 组件用于创建滚动区域,而 Text 组件则用于显示文本内容。

③ 通过设置 hitTestBehavior 为 HitTestMode.Block 来阻止文本区域的滑动行为,确保滚动仅发生在父级滚动区域中。

6. 适配不同屏幕尺寸:

① 为了确保组件在不同设备上的表现一致,可以考虑使用百分比布局或者动态计算容器尺寸的方法来适应不同屏幕尺寸。

② 通过设置 Scroll 组件的 constraintSize 属性,限制其最大高度为 pageHeight 或默认值 1000,以确保内容不会超出当前页面的高度。

7. 动态计算内容高度:

① 通过监听 Scroll 组件的 onAreaChange 事件,当容器高度发生变化时,重新计算 pageHeight 和 totalPages。

② 这样可以确保组件能够动态地适应不同的屏幕尺寸和内容长度,避免内容溢出或遮挡问题。

【为何不使用 textOverflow?】

① 无法直接获取截断后的内容: textOverflow 主要用于处理文本过长时的显示问题,但不能直接获取到文本被截断后的内容。这使得在分页时难以准确判断当前页面显示的是文本的哪一部分。

② 难以实现分页逻辑: 由于 textOverflow 不提供获取截断文本内容的API,因此难以实现精确的分页逻辑,比如计算每页显示的内容范围。

③ 用户体验: 使用 Scroll 和 Text 的组合可以更好地控制文本的显示和分页,从而提供更平滑的阅读体验。

【总结】

通过上述步骤,构建了一个简单但功能完备的分页滚动文本组件,可用于展示长文本内容,适用于多种场景。用户可以方便地通过“上一页”和“下一页”按钮浏览不同页面,而无需担心内容的显示问题。

相关文章:

  • C++不同的头文件中各种函数的操作使用(长期更新,找到新的就补充进来)
  • IntelliJ IDEA 2024.1.4 (Ultimate Edition)找不到Add Framework Support解决方法
  • 【MySQL】基本查询
  • 侧边菜单的展开和折叠
  • 领域驱动DDD三种架构-分层架构、洋葱架构、六边形架构
  • 通过openAI的Chat Completions API实现一个支持追问的ChatGPT功能集成
  • 初试AngularJS前端框架
  • 【AI驱动 TDSQL-C Serverless 数据库技术实战营】AI赋能电商数据管理
  • 【AI大模型】向量及向量知识库
  • C++的智能指针
  • Java爬虫抓取数据的艺术
  • 电脑ip地址怎么换地区:操作步骤与利弊分析
  • 【学习笔记】TLS/SSL握手之Records
  • 智能新宠:BabyAlpha A2开启家庭机器人新时代
  • 【JAVA】synchronized 关键字的底层实现涉及得三个队列
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • Linux快速复制或删除大量小文件
  • mac修复ab及siege安装
  • MaxCompute访问TableStore(OTS) 数据
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • springboot_database项目介绍
  • ucore操作系统实验笔记 - 重新理解中断
  • 从tcpdump抓包看TCP/IP协议
  • 高度不固定时垂直居中
  • 基于axios的vue插件,让http请求更简单
  • 算法---两个栈实现一个队列
  • 小程序 setData 学问多
  • 因为阿里,他们成了“杭漂”
  • 用简单代码看卷积组块发展
  • ​​​【收录 Hello 算法】9.4 小结
  • (2024最新)CentOS 7上在线安装MySQL 5.7|喂饭级教程
  • (3)选择元素——(17)练习(Exercises)
  • (35)远程识别(又称无人机识别)(二)
  • (HAL库版)freeRTOS移植STMF103
  • (NSDate) 时间 (time )比较
  • (php伪随机数生成)[GWCTF 2019]枯燥的抽奖
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (windows2012共享文件夹和防火墙设置
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (四)汇编语言——简单程序
  • (转)Scala的“=”符号简介
  • (转)重识new
  • ******之网络***——物理***
  • .net 7和core版 SignalR
  • .net core docker部署教程和细节问题
  • .NET MVC之AOP
  • .Net Remoting常用部署结构
  • .NET大文件上传知识整理
  • .NET设计模式(11):组合模式(Composite Pattern)
  • /var/lib/dpkg/lock 锁定问题
  • [ CTF ] WriteUp-2022年春秋杯网络安全联赛-冬季赛
  • [2018][note]用于超快偏振开关和动态光束分裂的all-optical有源THz超表——
  • [Algorithm][动态规划][子序列问题][最长递增子序列][摆动序列]详细讲解
  • [Angularjs]asp.net mvc+angularjs+web api单页应用