想要用RN写个小说APP第三天【文章分页📚】
在某天某时,我立下了这个奇怪的flag,关于我和他的爱恨情仇,请看我的第一篇文章 想要用RN写个小说APP第一天 当前已经实现的功能有:
- 爬取页面内容
- 状态管理以及数据持久化
- 小说内容主题自定义(字体/颜色/...)
- 爬取后如何进行文本分页✅
- 分页后如何在用户阅读时,无感加载上/下一章
- (相关的bug经历我最近都会写出来🧐🧐🧐) 项目地址,star看我后续更新🌠🌠🌠
今日内容
如何准确的得到当前页面能够显示的页面内容
第一次构思
今天的内容是我写这个APP目前遇到的第二痛苦的功能(第一是无感加载分章)。自己看小说时,就这样一页一页的翻过去,甚至在我开始做这个功能之前。也没有察觉到一个大难题已经挡在了我面前。当我信心满满的敲下:
const Content:React.FC = () =>{
return <View>....???.</View>
}
下一刻...?我该怎么办,将全部小说章节内容文本渲染到页面后,怎么把文本换成多页?我承认我抓瞎了。无从下手,这个的唯一难点就是,在一串连续的的文本中,我该如何知道当前页面能够填充的字符数,将其准确的截断。经过自己的简单思考后,一个粗略的想法出来了:通过字体大小(fontSzie)计算屏幕宽度一行能够容纳的字数,再通过屏幕高度除以行高,得到一页能够显示的文本总行数,最后相乘得到一页可以显示的字数
。有了这个想法,我真的下手如有神,写下了这样一段代码:
export default function Test({content}: {content: string}) {
const fontSize = 30,
lineHeight = 50;
const width = useWindowDimensions().width;
const height = useWindowDimensions().height;
const count = (width / fontSize) * (height / lineHeight);
return (
<View>
{[0, 1, 2, 3, 4, 5].map(_ => (
<Text style={{padding: 30, fontSize: 80}}>
{content.slice(_ * count, _ * count + count)}
</Text>
))}
</View>
);
}
显而易见的,这样确实有点效果,但他是失败的~~~~ ,他大概可以分出对应页数,这个是对的,但是每一页的内容中,都有着较大的缺口才能够填满整个页面,显示出来大概是这样的:
在红框部分,大概还需要一行半的内容才能填满屏幕,经过一阵折腾过后,我发现了大概的原因,同一fontSize
下标点符号数字以及英文字母与汉字的宽度并不相同。然后我就.....
二次重构
发动了我的搜索技能,在gathub以及搜索引擎的帮助下,我拿到了大概这样的一段代码,他的功能以及逻辑大概是这样的:
将一个中文汉字定义为宽度2 英文大写字母是1.1(大概的数值,具体忘了) 英文小写字母是0.9(大概的数值,具体忘了) 各种标点符号定义的范围是(1,1.5) 经过这样的定义后,首先还是要算出一行能够容纳的汉字额个数,得到的字数*2(因为上面我们将汉字宽度定义为数值2) 下一步:定义一个行内容数组,从头遍历文章内容,每一次获取到的字符都要通过上面的方法得到定义的长度,对字符串长度相加的结果(要加上下一次要加上的字符长度)与一行可容纳的长度进行对比,当结果是大于时,说明再加上下一个字符就会超出当前行了,这时候将之前的字符串截取出存入数组,再重复上面的过程,就等到了了一个由文章每一行内容的字符串数组,再计算得到一页可存入的函数,截取行数据数组。再进行遍历显示。 这个方法的显示效果很好的,大概如下:
中间插曲
能够写到这,说明上面的方案还是有问题的。上面的方案并非我初次搜寻就得到的,我先是得到了,一篇文章,他的内容是关于起点小说是如何在浏览器中将小说进行水平分页的。文章的重点就是就是一个CSS属性:columns
,这个属性能够将一个元素的内容,在给定元素高度中将内容进行分块显示。犹如旱田遇甘露🚿🚿🚿。我立马去试了这个方案,然后得到了....是的,react-native
并不支持这个CSS属性。
问题
上面的统计长度的方案中,我试了很多个章节都发现有着较好的显示效果,但我一阵开心过后。我突然有个想法,将内容的字体换成我平时最常用的~这也是我由喜转悲的开始。但我经过一整折腾过后,按下键盘的R
键(RN的开发工具通过这个控制应用Reload
),当页面出来时,我的心凉了一半,大概是这样的:
最终方案
当我想要说服自己放弃水平滑动,而变成更容易实现的垂直滑动,我在RN的Text组件文档中注意到了这样的一个字眼。
然后我有又在下面的类型定义中看到了
文本行
和数组
,看到这个两个词凑在一起时,我虎躯一震。立刻去测试了我的想法。最终我在Text
组件的回调事件onTextLayout
中,我得到了lines
数组,然后取出数组中的text
。
onTextLayout={({nativeEvent}) => {
console.log(nativeEvent.lines);
}}>
他的结构形式跟前面的方案是一样的,都是将每一行容纳的文本进行分割,但这次是由ReactNative
底层进行过一次布局之后再传出给我们。通过之前得到的每页可容纳行数,进行切割得到总页数。而我用于获取布局数组的Text
,则使用绝对定位absolute
以及可见度opacity
设置为0
,将其隐藏起来(事了拂衣去,深藏功与名)
。
noPlay: {
pointerEvents: 'none',
position: 'absolute',
left: 0,
top: 0,
opacity: 0,
},
结语
分页的这个功能断断续续的卡了我三天。但最终实现的时候,还是感觉我掉的头发是值得的🦳。
这次滴内容就写到这了,后续计划更新(打勾的已经更新了)的内容有: (下面计划的功能都是已经大致完成了💨)
- 搭建页面基础结构🎈
- 如何爬取页面内容💖
- 状态管理以及数据持久化🧡
- 小说内容主题自定义(字体/颜色/...)🤎
- 爬取后如何进行文本分页💘
- 分页后如何在用户阅读时,无感加载上/下一章💝
转载自:https://juejin.cn/post/7158827044350984206