简介:flutter富文本演进html
做者:闲鱼技术-新宿安全
在闲鱼消息体系中,富文本在 UI 侧占了很是大的比重。最近消息部分在总体 Flutter 化,如何解决 Flutter 侧富文本问题,成为了项目早期的风险点。编辑器
在 Native 中,消息使用了 HTML 协议来承载富文本的解析与展现,因为消息的历史数据有落库的特性,咱们必须在 Flutter 侧兼容这种协议。对于 Flutter,咱们是否能够在兼容的基础上,进行能力的扩充与完善?函数
当前闲鱼也在升级 Flutter 1.12,因此咱们不光要在当前版本支持图文混排,也须要快速迁移到高版本的系统方案。所以咱们须要找到一个兼容性高、易迁移的富文本方案。布局
行业内,对于旧版的 RichText (Flutter 1.7.3 以前)已有了解决方案,详见玄川:《如何低成本实现Flutter 富文本,看这一篇就够了!》。但这里并无对富文本的整个链路的解决思路,且 Flutter 自身的 RichText 也在随着版本迭代进行演进,咱们须要一套完整的演进方案。字体
事实上,Flutter 1.7.3 开始的 RichText 解决了咱们的不少麻烦,它是怎么实现的呢?和旧版的实现有什么区别呢?带着问题,咱们先来分析它的实现原理。ui
Flutter 1.7.3 开始,RichText 再也不继承自 LeafRenderObjectWidget,而是继承自 MultiChildRenderObjectWidget,从这就很容易看出,RichText 将是一个布局控件,内部能够有多个子控件。spa
如上图,咱们传给 RichText 的 text 参数为 InlineSpan,TextSpan、WidgetSpan都是其子类。设计
上图为 RenderParagraph 内的 performLayout 函数。3d
第二步 _layoutTextWithConstraints,就是执行 _textPainter 的 layout 方法,这里会让 text(InlineSpan)进行 build,此时会按照它的树形结构遍历执行。
归纳来讲,新版本对比旧版本,底层多了个 _addPlaceholder 能力,用来占位混排的 Widget,并获取位置信息。
咱们以 HTML 协议为抓手,不光能够解决普通 HTML 字符串的解析与渲染,也能够对用户发送的带闲鱼自定义 emoji 的字符串进行能力的扩充。下图为大体的设计思路:
当前消息展现分为两种场景,一种为带有闲鱼自定义 emoji 表情的字符串:
你好[微笑],你的宝贝不错哦[呲牙],包邮吗?[坏笑][坏笑]
另外一种为简单的 HTML 字符串:
"<font color="#888888">交易全程在闲鱼,</font><strong><font color="#F54444">你敢买,我敢赔!</font></strong><font color="#888888">若遇欺诈形成</font><strong><font color="#F54444">钱货两失,可获赔</font></strong><strong><font color="#F54444">最高5000元</font></strong>"
固然,还有最普通的纯文本。
对于这三种字符串,服务端并无用类型来给咱们区分,客户端拿到的都为字符串。端侧该如何处理且高效展现呢?
过程设计成这样:
RegExp(r'\[[^\]\[]+\]')
匹配[微笑]
等 emoji 占位符,替换为<img src=003_微笑.png width=22.400000 height=22.400000/>
递归 HTML Node Tree
流程上,先将闲鱼自定义 emoji 占位符转为 HTML 元素,接着统一处理 HTML 字符串。而后将 HTML 字符串统一转为富文本。设计上,分为两层:数据解析层、渲染层。
如上图,有了前面原生 Flutter 图文混排支撑,咱们在低版本能够仿照实现,低版本 RichText 继承自 LeafRenderObjectWidget,咱们把 RichText 与其余 Widget 组成新的 MultiChildRenderObjectWidget,经过占位符正常渲染文本,以后获取占位符位置,设置对应 Widget 的位置。
Flutter SDK 升级过程当中如何保持业务方无感知?先看下图:
对比发现,在 TextSpan 树中,咱们继承自 TextSpan 的自定义 FDImageSpan,实际上能够直接对应到原生的 WidgetSpan,这里咱们能够在 HTML Node Tree 映射到 TextSpan Tree 的过程当中直接修改。而 FDRichText build 里,咱们能够直接返回系统 RichText。这样的改动,对于使用方能够作到无感知。
上图中是一种最为简单和常见的系统消息,为了突出安全警示,使用了较多的红色字体。模块中定义的三个富文本,都可定制样式。
上图为涉及交互的富文本,买家能够点击蓝色文字「那儿发货」,而后买家会自动发送「那儿发货」给卖家,卖家会根据预设的问题自动回复买家。点击会触发 HTML 字符串中的 href 自定义协议连接,客户端会触发 openURL 的操做,以此来实现交互。
这是普通用户能够编辑发送的富文本,丰富的闲鱼自定义 emoji,穿插在文字中,不只增长了聊天乐趣,也加强了用户的表达。
当前的展现部分仅仅是图文混排,新版本中的富文本支持任意 Widget,可玩性更高,因此咱们对 HTML 标签描述能够进行扩充,这部分将来还须要持续探索。
因为篇幅有限,上文并无讲述富文本编辑器。消息中用户输入框也需支持闲鱼自定义 emoji,当前版本的方案为直接使用占位符(好比“[微笑]”),并不展现实际的图片。咱们回头再看一下 HTML 协议,对于新版的 TextField,咱们能够支持吗?这就不只仅局限在自定义 emoji 里了。
咱们把目光转向发布和宝贝详情:
咱们后续可能会支持上图中,发布和宝贝详情的富文本编辑和展现。对比两个详情页,很明显能看出,使用富文本的方式,在表达上更加富有冲击力,买家阅读起来能很容易抓住卖家想表达的关键信息。
可见,将来在富文本的编辑、展现基础能力统一以后,可让更多业务收益。