一个易迁移、兼容性高的 Flutter 富文本方案
-
RichText 初始化过程中会将 text 中的所有 WidgetSpan 递归筛选出来,传递给父类 MultiChildRenderObjectWidget。
-
创建 MultiChildRenderObjectElement,接着 RichText 会通过 createRenderObject,生成 RenderParagraph。
-
RenderParagraph 初始化过程中会创建 TextPainter,这个是绘制的核心,这里将会进行 layout、paint 和事件分发操作;然后递归筛选 PlaceholderSpan (其实还是 WidgetSpan)。
-
如上图 RenderParagraph 执行 performLayout 。首先 _layoutChildren:为子控件布局,目的为获取子控件大小,如果没有子控件则直接 return。这里所说的子控件就是 WidgetSpan。
-
第二步 _layoutTextWithConstraints,就是执行 _textPainter 的 layout 方法,这里会让 text(InlineSpan)进行 build,此时会按照它的树形结构遍历执行。
-
TextWidget build 时会将自身的 text(这是真实的字符串)addText 给 builder。
-
WidgetSpan build 时会将自身控件的 PlaceholderDimensions 信息,addPlaceholder 给 builder。这里其实就是添加占位符,占位符将与控件同大小。
-
紧接着 _paragraph 会进行一次布局,然后获取各个占位符位置存储下来。
-
Paint 过程会先将带着占位符的文本绘制完成,然后遍历子控件按照 2-3 步骤中获得的占位符位置,设置偏移。

你好[微笑],你的宝贝不错哦[呲牙],包邮吗?[坏笑][坏笑]
另一种为简单的 HTML 字符串:
"<fontcolor="#888888">交易全程在闲鱼,</font><strong><fontcolor="#F54444">你敢买,我敢赔!</font></strong><fontcolor="#888888">若遇欺诈造成</font><strong><fontcolor="#F54444">钱货两失,可获赔</font></strong><strong><fontcolor="#F54444">最高5000元</font></strong>"
当然,还有最普通的纯文本。
对于这三种字符串,服务端并没有用类型来给我们区分,客户端拿到的都为字符串。端侧该如何处理且高效展示呢?
过程设计成这样:
-
首先对于确定为纯文字的控件,直接使用单 TextSpan 的 RichText,免去 Text 的封装。
-
使用
RegExp(r'\[[^\]\[]+\]')
匹配[微笑]
等 emoji 占位符,替换为<imgsrc=003_微笑.pngwidth=22.400000height=22.400000/>
-
取最后的 HTMLString ,使用 html | Dart Package ,进行 HTML 解析,生成 HTML Node Tree
-
递归 HTML Node Tree
-
文本标签映射为 TextSpan
-
图片标签映射为 FDImageSpan;Flutter 升级后将其替换为 WidgetSpan,其 child 设置为 Image Widget
-
链接标签映射为 TextSpan,定义 GestureRecognizer 相应手势






闲鱼技术团队不仅是阿里巴巴集团旗下闲置交易社区的创造者,更是移动与高并发大数据应用新技术的引导者与创新者。我们与 Google Flutter/Dart小组密切合作,为社区贡献了多个高 star的项目和大量PR 。我们正在积极探索深度学习和视觉技术在互动、交易、社区场景的创新应用。闲鱼技术与集团中间件团队共同打造的FaaS 平台每天支持数以千万级用户的高并发访问场景。
就是现在!客户端/服务端java/架构/前端/质量 工程师面向社会+校园招聘,base杭州阿里巴巴西溪园区,一起做有创想空间的社区产品、做深度顶级的开源项目,一起拓展技术边界成就极致!
*投喂简历给小闲鱼→guicai.gxy@alibaba-inc.com


转载自:https://juejin.cn/post/6844904128926203917