簡介: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 裏了。
咱們把目光轉向發佈和寶貝詳情:
咱們後續可能會支持上圖中,發佈和寶貝詳情的富文本編輯和展現。對比兩個詳情頁,很明顯能看出,使用富文本的方式,在表達上更加富有衝擊力,買家閱讀起來能很容易抓住賣家想表達的關鍵信息。
可見,將來在富文本的編輯、展現基礎能力統一以後,可讓更多業務收益。