前言
做了个富文本编辑器,先给大家看看效果: 【潜心研究一年,开发的笔记软件】
之前有个朋友私信我说,既然你的笔记软件收费了,能不能出点富文本的教学?
不是我不想出,实在是太复杂了呀 >_>!
我先写一篇,看看大家能不能看懂,如果写得都能看懂的话,那后面出一期教学又有何妨。
富文本编辑器需要解决以下几个难题(不仅仅):
- 编辑协议(数据结构)
- 选择器
- 数据渲染
- 富文本html解析
- 撤销重做
- 输入法对接
- 复制粘贴
富文本元素
首先看看有哪些富文本元素:
- 文本
- 标题
- 链接
- 公式
- 代码块
- 表格
- 分割线
- 图片
- 列表
- 有序列表
- 引用
对这些元素进行分类,行内元素有:
- 文本
- 标题
- 链接
- 公式
块元素有:
- 代码块
- 表格
- 图片
- 列表
- 有序列表
- 引用
对于行内元素,使用flutter自带的 RichText 即可实现,对于块元素,就需要单独处理。
例如图片元素,可以自定义一个图片 Widget。
数据渲染
为了提高渲染性能,渲染部分设计成局部渲染,按需加载。
即将内容分成行,内容由一行行块元素组成,块元素内部会包含行内元素。
渲染时,每个行块给个预设尺寸,等元素出现到视图中时,才会计算元素的真实尺寸。
当然真实尺寸其实也可以缓存到数据结构中,增加性能,但也会增加数据体积。
对于块元素,用一个抽象类 Block 表示。
整个界面通过 Scrollable + Stack 组件实现。
在滚动视图 Scollable 进行滚动时,需要根据 Block 尺寸计算出现在视野中的 Block。
在 Widget 的 layout 阶段,通过 ViewportOffset 的 applyViewportDimension 和 applyContentDimensions 通知滚动视图刷新视野尺寸和内容尺寸。
因此,我们可以在layout阶段根据预设尺寸计算可能出现在视野中的Block,再去计算出可能现在视野中的Block真实尺寸,进而刷新真实内容尺寸,然后将尺寸交给 ViewportOffset 即可处理滚动了。
有点类似微积分,在滚动过程中不断计算尺寸,ViewportOffset 会自动处理滚动逻辑,无需我们多做什么。
选择器
选择富文本内容时,需要根据点击坐标计算得到光标位置。
如何描述光标位置?不妨想想如何确定光标位置。
光标在哪一行?在这行的那个位置?
对于文本元素,就是第几行 + 第几个文字。
对于图片元素,就是第几行 + 0/1,0指的时图片前面,1指的是图片后面。
对于表格元素,就是第几行 + 第几表格列 + 第几表格行 + 第几个文字,但可以通过数学索引包含表格内行列位置,化简成第几行 + 第几个文字。
其它的元素也都可以化简成第几行+第几个文字的形式,不一一列举。
输入法对接
在 flutter 中,通过 TextInput.attach 即可完成输入法的接入。
在 attach 后,会返回一个 TextInputConnection 对象,通过这个 connect 对象与输入法完成交互。
需要结合 FocusNode,监听 Focus 变化,在聚焦时打开输入法,在非聚焦时关闭输入法。
通过以下代码更新内容到拼音输入法
void updateEditingValue(TextEditingValue value) {
if (!value.composing.isValid) {
if (value.text.isNotEmpty) {
inputCallback?.call(value);
connection