搭建小说系统源码,如何实现读书的分页功能
目标
- 使用
TextKit
快速分页 - 使用
UIPageViewController
支持平台
iOS, iPadOS
也许还支持 Mac Calalyst
?
使用语言
Swift
视图结构
|- UIViewController // 根视图, 可添加菜单显示, 手势操作等|- UIPageController // 章节视图, 一页对应一章| - UIPageController // 章节内容分页视图, 将单章内容进行分页显示| | - UIViewController // 单页显示视图, 对应单页数据| | |- UITextView // 文字视图| || | - UIViewController| | |- UITextView| || | ...|| - UIPageController| | - UIViewController| | |- UITextView| || | - UIViewController| | |- UITextView| || | ...|| ...
小说系统源码的章节内容分页视图中, 只要在返回单页显示视图的代理中返回
nil
, 即可实现章节内容翻到最后一页时, 继续翻页翻到下一章节的逻辑
分页实现
首先, 一定要先确定
好 TextView 的大小与内容间距, 即文字显示区域的大小
, 这将严重影响到分页后的数据能不能正常显示
其次, 首行缩进最好用空格代替, 而不是用 NSParagraphStyle
的 firstLineHeadIndent
属性来实现, 否则会出现某段落从中间被分开, 下一页依然被缩进的情况
首行缩进的空格数量可用以下逻辑计算:
let normalWidth = "你好".size(font: textFont).width // 请根据内容语言改变文字
let speaceWidth = " ".size(font: textFont).width // 一个空格的宽
let speaceCount = Int(normalWidth / speaceWidth)
let speace = String(repeating: " ", count: speaceCount)
然后在每段前添加空格
let result = content.string.components(separatedBy: "\n").map { "\(speace)\($0)" }
这样就可以在每段首行添加一个合适的缩进了
接下来就是重点的分页了
第一步, 前期参数准备:
准备好处理完成的
NSAttributedString
, 最好包含各种字体, 颜色, 格式等设置信息, 避免分页视图拿到数据后再次生成NSAttributedString
, 重复设置内容样式导致的分页不准的情况准备好文字显示区域大小的参数
第二步, 开始分页:
准备数据:
// 创建 NSLayoutManager, 所有的分页逻辑开端
let layoutManager = NSLayoutManager()// 如果没有给特定部分文字区域设置单独的布局, 可设置此项为 false, 以提高性能
layoutManager.allowsNonContiguousLayout = false// 使用之前准备好的 NSAttributedString 进行初始化 NSTextStorage
let textStorage = NSTextStorage(attributedString: string)
textStorage.addLayoutManager(layoutManager)// 设定文字显示区域参数
let viewSize: CGSize = CGSize(width: textAreaWidth, height: textAreaHeight)// 设定 textView 的内间距
let textInsets = UIEdgeInsets.zero
let textViewFrame = CGRect(x: 0, y: 0, width: viewSize.width, height: viewSize.height)// 开始分页
var glyphRange: Int = 0
var numberOfGlyphs: Int = 0
分页循环:
var ranges: [NSRange] = []
repeat {let textContainer = NSTextContainer(size: viewSize)layoutManager.addTextContainer(textContainer)// 不断创建 textView 让 NSLayoutManager 进行内容分页let textView = UITextView(frame: textViewFrame, textContainer: textContainer)textView.isEditable = falsetextView.isSelectable = falsetextView.textContainerInset = textInsetstextView.showsVerticalScrollIndicator = falsetextView.showsHorizontalScrollIndicator = falsetextView.isScrollEnabled = false // 禁止滑动, 否则计算结果将不再准确textView.bounces = falsetextView.bouncesZoom = false// 获取当前分页内容所在位置let range = layoutManager.glyphRange(for: textContainer)ranges.append(range)// 判定是否分页完成glyphRange = NSMaxRange(range)numberOfGlyphs = layoutManager.numberOfGlyphs
} while glyphRange < numberOfGlyphs - 1
CoreText
版本:
var ranges: [NSRange] = []
let framesetter = CTFramesetterCreateWithAttributedString(string)
var textPosition = 0
while textPosition < string.length {let path = CGPath(rect: textViewFrame.inset(by: textInsets), transform: nil)let frame = CTFramesetterCreateFrame(framesetter, .init(location: textPosition, length: 0), path, nil)let stringRange = CTFrameGetVisibleStringRange(frame)let range: NSRange = .init(location: stringRange.location, length: stringRange.length)textPosition += stringRange.lengthranges.append(range)
}
至此, 就得到了带有格式的全文 NSAttributedString
, 和分页区域的 ranges
第三步, 显示分页数据,小说系统源码的章节内容分页视图中, 将单章的 NSAttributedString
和分到的 range
分配给每一个单页显示视图, 在 UITextView
中直接设置 attributedText
为 attributedString.attributedSubstring(from: range)
UITextView
的设置务必于分页循环时的 UITextView
保持一致
声明:本文由云豹科技转发自Norld博客,如有侵权请联系作者删除
搭建小说系统源码,如何实现读书的分页功能相关推荐
- java计算机毕业设计在线小说系统源码+系统+mysql数据库+lw文档
java计算机毕业设计在线小说系统源码+系统+mysql数据库+lw文档 java计算机毕业设计在线小说系统源码+系统+mysql数据库+lw文档 本源码技术栈: 项目架构:B/S架构 开发语言:Ja ...
- ptcms模板自动采集小说系统源码
介绍: ptcms模板自动采集小说系统源码安装教程: mysql,php5.6 必须安装扩展:ZendGuardLoader 脚本解密 ionCube 脚本解密 fileinfo 通用扩展 opcac ...
- 最新4合1小说系统源码 (音乐、漫画、视频自动采集)
软件介绍: 最新4合1小说系统源码 (音乐.漫画.视频自动采集),带完整教程,适合萌新运营,欢迎下载使用. 下载地址:https://download.csdn.net/download/m0_71 ...
- PACS/RIS系统源码 支持专业三维影像后处理功能,支持海量数据存储、迁移管理
PACS系统源码 支持专业三维影像后处理功能,系统有演示和自主知识产权. 私信了解更多内容! 系统主要功能: (一)影像处理 1.数据接收功能:接收.获取影像设备的DICOM3.0和非DICOM3.0 ...
- 婚恋交友系统源码开发容易忽视的定位功能
本文旨在阐释清楚婚恋交友系统源码的GPS相关开发过程中经常遇到的一些问题,涉及GPS版本变化.定位获取失败等常见问题:以减少大家信息获取的负担为宗旨.GPS本身并不复杂,但是因为GPS定位慢外加一些限 ...
- 最新帝国CMS花生小说系统源码+花生日记引流导航模板+带采集工具
正文: 一个专注小说阅读细化分类的网站. 说明:小说公众号导航站模板,小说网站导航引流网站源码,网站结构清晰优化得好容易收录. 本站带火车自动采集,带手机端,并且有同步生成插件,采用帝国cms7.5内 ...
- 最新PTCMS小说系统源码_精美多风格四套全新版源码_模板.zip
下载地址:http://sucaiip.com/company-275.html
- 2023最新UI拉拉米抢单发单系统源码/二开带教程/放量功能
正文: 服务器系统:Linux+宝塔 亲测环境:Nginx1.16.1+PHP5.6+Mysql5.5 修改数据库配置文件:/config/database.php 运行目录设置:/public 短信 ...
- 最新74cms骑士人才招聘系统源码SE版V3.16.0/功能强大
正文: 74cms骑士人才招聘系统是一项基于PHP+MYSQL为核心开发的一套开源专业人才招聘系统. 骑士人才系统拥有十多年的人才招聘系统运营解决方案,同时我们提供智能化招聘系统.招考系统等全方位系统 ...
最新文章
- Google 选择 Jetty 放弃 Tomcat
- 音视频互动开发平台之AnyChat SDK
- 活动 | Daung~!他们用产品思维改变医疗挂号问题
- 如何改变本地git的根目录
- 北斗信号服务器解算,GPS/北斗定位解算算法的研究
- Asp.net在线备份、压缩和修复Access数据库
- 12864液晶使用例程
- (95)分频器设计(偶数分频)
- 深度学习之dropout
- 测试~在使用共通处理时,需要注意的问题 ~ 使用前,清空Form中的值。
- 面向对象之自动绑定数据源
- [渝粤教育] 重庆电子工程职业学院 物联网工程导论 参考 资料
- WINX新增(1): KMP字符串查找算法
- 华为路由器怎么配置虚拟服务器,华为路由器配置实例详细备注讲解
- 社会化分享(附源码)
- 人工智能发展神速?37年前的尘封档案告诉你并没有
- Unity3D 模型描边插件Outline Effect详细使用说明、C#功能扩展
- 关注电动汽车能效水平 提高续航能力
- 图像处理(一):傅里叶变换简单讲解
- 牛顿迭代法求一个数的平方根(python)
热门文章
- 长沙有哪些比较有名的互联网公司?
- Lucene.net(4.8.0)+PanGu分词器 问题记录一 分词器Analyzer的构造和内部成员ReuseStategy
- 使用Arduino和GSM模块进行呼叫和消息
- 软件工程23种设计模式全解析
- AspectJ使用实例
- 武田将在即将召开的虚拟科学大会上呈报数据,强调肿瘤产品阵容和后续产品管线的广度
- 基于OHCI的USB主机 —— UFI读容量代码
- 关于移动通讯的发展史及5G的各项技术与面临的挑战阐述
- 周星驰经典对白 (不可不看哦)[转贴]
- 疯狂Java讲义(十三)----第五部分