iOS Epub阅读器改造记录
六个月前在这个YHEpubDemo阅读器的基础上做了一些优化,这里做一下记录。
1.首行缩进修复
由于分页的存在,新的一页的首行可能是新的一行,则应该缩进;也可能是前面一页段落的延续,这时候不应该缩进。YHEpubDemo基于XDSReader,XDSReader目前存在新页首行没有缩进的问题。
修复方案如下:
原来预排版分页后将每一页的富文本设置给XDSReadView,这样就失去了排版的连续性。现在改为将整个章节的富文本设置给XDSReadView,并且对该页需要显示的文本范围进行布局。
在XDSReadView.m的reloadView底部加上以下代码:
CGRect rect = UIEdgeInsetsInsetRect(self.readTextView.bounds, self.readTextView.edgeInsets);DTCoreTextLayoutFrame *layoutFrame = [self.readTextView.layouter layoutFrameWithRect:rect range:_pageRange];self.readTextView.layoutFrame = layoutFrame;
因为前面我们已经给readTextView设置了整个章节的富文本:
self.readTextView.attributedString = self.readAttributedContent;
因此我们这里要根据布局区域的大小和布局文本的范围,使用layouter来产生一个layout frame。这样产生的布局是具有连续性的。如果仍然使用原来分页的方式的话,需要判断当前页第一行开始处,是否位于上一页的段落中。如果不在其中,而是新的段落,就要获取上一页段落的样式中的headIndent,将其设置给当前页第一行样式中的firstLineHeadIndent。
2.CSS rem修复
XDSReader基于DTCoreText,DTCoreText有自己的css和HTML解析器,但是不支持css的rem特性,这样会导致字体大小有问题。由于DTCoreText没有提供root element上下文,目前暂时将rem当em处理,虽然会有一些误差,但不至于字体大小变1pt。
3.树形目录
根据epub规范,我们是可以解析获得任意多级的目录的。考虑到目录可以折叠展开,当我们获得了树形数据结构后,我们可以使用BFS(宽度优先遍历)来实现目录的打平:
- (void)reloadData
{self.catalogs = [NSMutableArray arrayWithArray:CURRENT_BOOK_MODEL.catalog.children];NSMutableArray *q = [NSMutableArray arrayWithArray:CURRENT_BOOK_MODEL.catalog.children];while (q.count > 0) {XDSCatalogueModel *top = q[0];[q removeObjectAtIndex:0];if(top.isExpand){[q addObjectsFromArray:top.children];NSInteger idx = [self.catalogs indexOfObject:top];if(idx == NSNotFound){idx = -1;}[self.catalogs insertObjects:top.children atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(idx+1, top.children.count)]];}}[self.tableView reloadData];
}
首先我们将一级目录节点加入临时数组和结果数组,如果当前临时数组数组不为空,则取出第一个,并且从临时数组中移除。如果这个节点是展开的,就把这个节点的子节点加入临时数组。现在我们从结果数组中找到这个节点的位置,将它的子节点按顺序插入后面。像这样往复前面的操作,直到临时数组为空为止。最终我们得到了一个平坦的列表。
4.增加页码
增加页码就是在预排版和分页时,需要记录每一个章节的页码范围,每一页的文字范围等,然后据此计算页面所在的页码,以及页码所在的文字范围等。
5.textblock背景色修复
源码中会给textblock设置一个难看的深蓝色的背景色,在我们的修复中会首先尝试获取textblock的背景色,没有的话才设置为白色:
CGColorRef color = [textBlock.backgroundColor CGColor];if(!color){color = [[UIColor whiteColor] CGColor];}
6.其他
另外对阅读进度记录,添加note也做了一些修复。增加了水平滚动翻页类型。
最终的效果:



源码:GitHub - Mamong/YHEpubDemo: Epub 阅读器
后续考虑使用Swift重写,并将epub解析部分抽取出来。
相关文章:
iOS Epub阅读器改造记录
六个月前在这个YHEpubDemo阅读器的基础上做了一些优化,这里做一下记录。 1.首行缩进修复 由于分页的存在,新的一页的首行可能是新的一行,则应该缩进;也可能是前面一页段落的延续,这时候不应该缩进。YHEpubDemo基于XDS…...
负载均衡搭建
LVS-DR部署 [客户端] node1 192.168.157.148 [lvs] node2 192.168.157.142 [web服务器] node3 192.168.157.145 node4 192.168.157.146(1)[lvs] yum install -y ipvsadm.x86_64 配置LVS负载均衡服务 (1)手动添加LVS转发1ÿ…...
form表单input标签的23种type类型值?
当你学了很多技术以后,再回头看来,竟然被一个被一个基础问题虐了,23个类型值说不全,不是少这个,就是少那个,那么23种类型都有什么呢? text 单行文本输入框 password 密码输入框 file …...
python selenium如何保存网站的cookie用于下次自动登录
## 一、python selenium如何保存网站的cookie 使用Selenium保存网站的Cookie非常简单。下面是一个示例,展示了如何使用Selenium打开网站,然后保存获取到的Cookie: from selenium import webdriver# 初始化浏览器 browser webdriver.Chrome…...
DHCP Server
简介 动态主机配置协议 DHCP(Dynamic Host Configuration Protocol,动态主机配置协议) 是 RFC 1541(已被 RFC 2131 取代)定义的标准协议,该协议允许服务器向客户端动态分配 IP 地址和配置信息。 使用UDP协…...
DMR+PoC宽窄融合互通解决方案
当前,Tetra、PDT、DMR、P25等专网通信的主流窄带技术,能够保障在紧急情况下可靠的关键语音通信对讲,但随着行业用户对图片、视频、数据等宽带业务的需求越来越强烈,原本单一的语音通信早已无法满足用户对新需求。 北峰BF-SCP810 D…...
Springboot定时执行任务
定时任务 TaskScheduler 任务调度者 TaskExecutor 任务执行者 EnableScheduling//开启定时功能的注释 Scheduled(cron"* * * * * * *")//什么时候执行~ cron表达式(秒 分 时 日 月 星期 ) Cron表达式 主启动类加上注解开启任务调度 package com.qf.sping09te…...
【Apollo】阿波罗自动驾驶:塑造自动驾驶技术的未来
前言 Apollo (阿波罗)是一个开放的、完整的、安全的平台,将帮助汽车行业及自动驾驶领域的合作伙伴结合车辆和硬件系统,快速搭建一套属于自己的自动驾驶系统。 开放能力、共享资源、加速创新、持续共赢是 Apollo 开放平台的口号。百度把自己所拥有的强大、…...
JavaEE初阶:多线程 - Thread 类的基本用法
上次我们了解了多线程的五种创建方法,今天来学习Thread的基本用法。 目录 run和start Thread常见的构造方法 Thread的几个常见属性 后台线程 是否存活 线程终止 1.使用标志位 2.使用Thread自带的标志 等待线程 run和start 首先需要理解Thread的run和star…...
编写 loading、加密解密 发布NPM依赖包,并实施落地使用
你的 Loading 开箱即可用的 loading, 说明:vue3-loading 是一个方便在 Vue 3 项目中使用的加载指示器组件的 npm 插件。它允许您轻松地在项目中添加加载动画,提升用户体验。 目录 你的 Loading🌍 安装🛹 演示地址&…...
【剑指Offer 57】和为s的连续正数序列,Java解密。
LeetCode 剑指Offer 75道练习题 文章目录 剑指Offer:和为s的连续正数序列示例:限制:解题思路:剑指Offer:和为s的连续正数序列 【题目描述】 输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。 序列内的数字由小到大排列,不同序列按照首…...
深度学习实战基础案例——卷积神经网络(CNN)基于SqueezeNet的眼疾识别|第1例
文章目录 前言一、数据准备1.1 数据集介绍1.2 数据集文件结构 二、项目实战2.1 数据标签划分2.2 数据预处理2.3 构建模型2.4 开始训练2.5 结果可视化 三、数据集个体预测 前言 SqueezeNet是一种轻量且高效的CNN模型,它参数比AlexNet少50倍,但模型性能&a…...
麦肯锡发布《2023年度科技报告》!
在经历了 2022 年技术投资和人才的动荡之后,2023 年上半年,人们对技术促进商业和社会进步的潜力重新燃起了热情。生成式人工智能(Generative AI)在这一复兴过程中功不可没,但它只是众多进步中的一个,可以推…...
JAVASE---数组的定义与使用
数组的基本概念 什么是数组 数组是具有相同类型元素的集合,在内存中连续存储。 1. 数组中存放的元素其类型相同 2. 数组的空间是连在一起的 3. 每个空间有自己的编号,起始位置的编号为0,即数组的下标 数组的创建及初始化 数组的创建 T[…...
211、仿真-基于51单片机土壤湿度智能盆栽灌溉报警Proteus仿真设计(程序+Proteus仿真+配套资料等)
毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、硬件设计 二、设计功能 三、Proteus仿真图 四、程序源码 资料包括: 需要完整的资料可以点击下面的名片加下我,找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方案一&am…...
记录TensorRT8.5.0安装
1.下载网址NVIDIA TensorRT 8.x Download | NVIDIA Developer TensorRT不同的版本依赖于不同的cuda版本和cudnn版本。根据自己电脑的cuda版本和cudnn版本来决定要下载哪个TensorRT版本 查看cudnn版本 cat /usr/local/cuda/include/cudnn.h | grep CUDNN_MAJOR -A 2 cat /usr/l…...
flutter ListView 滚动到最后一个items位置
flutter 想要实现一个listview初始化时和数据变化后显示到列表的最末,简单地说就是像聊天窗或者是日志输出那样的情景。 要在Flutter中实现在初始化时和数据变化后将ListView自动定位到最后一个item的位置,你可以使用ScrollController来控制滚动位置&am…...
WMS:SurfaceView绘制显示
WMS:SurfaceView绘制显示 1、SurfaceView控件使用1.1 Choreographer接受VSync信号1.2 自定义SurfaceView1.3 结果 2、SurfaceView获取画布并显示2.1 SurfaceHolder.lockCanvas()2.2 SurfaceHolder.unlockCanvasAndPost(Canvas canvas) 1、SurfaceView控件使用 1.1 Choreograph…...
【Spring系列篇--关于IOC的详解】
目录 面试经典题目: 1. 什么是spring?你对Spring的理解?简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。 2.什么是IoC?你对IoC的理解?IoC的重要性?将实例化对象的权利从程序员…...
__ob__: Observer 后缀的数组的取值方式
开发中,经常从接口、父组件中,拿到数组然后给新的数组使用, 但是,有时候会发现带有 __ob__: Observer 后缀的数组,对这种数组来说,你是无法取到这个数组的值的, 而且,离谱的是consol…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...
Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...
pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决
问题: pgsql数据库通过备份数据库文件进行还原时,如果表中有自增序列,还原后可能会出现重复的序列,此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”,…...
ArcGIS Pro+ArcGIS给你的地图加上北回归线!
今天来看ArcGIS Pro和ArcGIS中如何给制作的中国地图或者其他大范围地图加上北回归线。 我们将在ArcGIS Pro和ArcGIS中一同介绍。 1 ArcGIS Pro中设置北回归线 1、在ArcGIS Pro中初步设置好经纬格网等,设置经线、纬线都以10间隔显示。 2、需要插入背会归线…...
结构化文件管理实战:实现目录自动创建与归类
手动操作容易因疲劳或疏忽导致命名错误、路径混乱等问题,进而引发后续程序异常。使用工具进行标准化操作,能有效降低出错概率。 需要快速整理大量文件的技术用户而言,这款工具提供了一种轻便高效的解决方案。程序体积仅有 156KB,…...
从零手写Java版本的LSM Tree (一):LSM Tree 概述
🔥 推荐一个高质量的Java LSM Tree开源项目! https://github.com/brianxiadong/java-lsm-tree java-lsm-tree 是一个从零实现的Log-Structured Merge Tree,专为高并发写入场景设计。 核心亮点: ⚡ 极致性能:写入速度超…...
