景
在閑魚消息體系中,富文本在 UI 側占了非常大的比重。最近消息部分在整體 Flutter 化,如何解決 Flutter 側富文本問題,成為了項目早期的風險點。
在 Native 中,消息使用了 HTML 協議來承載富文本的解析與展示,由于消息的歷史數據有落庫的特性,我們必須在 Flutter 側兼容這種協議。對于 Flutter,我們是否可以在兼容的基礎上,進行能力的擴充與完善?
當前閑魚也在升級 Flutter 1.12,所以我們不光要在當前版本支持圖文混排,也需要快速遷移到高版本的系統方案。因此我們需要找到一個兼容性高、易遷移的富文本方案。
行業現狀
行業內,對于舊版的 RichText (Flutter 1.7.3 之前)已有了解決方案,詳見玄川:《如何低成本實現Flutter 富文本,看這一篇就夠了!》。但這里并沒有對富文本的整個鏈路的解決思路,且 Flutter 自身的 RichText 也在隨著版本迭代進行演進,我們需要一套完整的演進方案。
事實上,Flutter 1.7.3 開始的 RichText 解決了我們的很多麻煩,它是怎么實現的呢?和舊版的實現有什么區別呢?帶著問題,我們先來分析它的實現原理。
RichText圖文混排原理
Flutter 1.7.3 開始,RichText 不再繼承自 LeafRenderObjectWidget,而是繼承自 MultiChildRenderObjectWidget,從這就很容易看出,RichText 將是一個布局控件,內部可以有多個子控件。
創建過程
如上圖,我們傳給 RichText 的 text 參數為 InlineSpan,TextSpan、WidgetSpan都是其子類。
RichText 初始化過程中會將 text 中的所有 WidgetSpan 遞歸篩選出來,傳遞給父類 MultiChildRenderObjectWidget。
創建 MultiChildRenderObjectElement,接著 RichText 會通過 createRenderObject,生成 RenderParagraph。
RenderParagraph 初始化過程中會創建 TextPainter,這個是繪制的核心,這里將會進行 layout、paint 和事件分發操作;然后遞歸篩選 PlaceholderSpan (其實還是 WidgetSpan)。
渲染過程
上圖為 RenderParagraph 內的 performLayout 函數。
如上圖 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 步驟中獲得的占位符位置,設置偏移。
概括來說,新版本對比舊版本,底層多了個 _addPlaceholder 能力,用來占位混排的 Widget,并獲取位置信息。
設計思路
我們以 HTML 協議為抓手,不光可以解決普通 HTML 字符串的解析與渲染,也可以對用戶發送的帶閑魚自定義 emoji 的字符串進行能力的擴充。下圖為大致的設計思路:
當前消息展示分為兩種場景,一種為帶有閑魚自定義 emoji 表情的字符串:
你好[微笑],你的寶貝不錯哦[呲牙],包郵嗎?[壞笑][壞笑]
另一種為簡單的 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 相應手勢
流程上,先將閑魚自定義 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 里了。
我們把目光轉向發布和寶貝詳情:
我們后續可能會支持上圖中,發布和寶貝詳情的富文本編輯和展示。對比兩個詳情頁,很明顯能看出,使用富文本的方式,在表達上更加富有沖擊力,買家閱讀起來能很容易抓住賣家想表達的關鍵信息。
可見,未來在富文本的編輯、展示基礎能力統一之后,可以讓更多業務收益。
閑魚技術團隊不僅是阿里巴巴集團旗下閑置交易社區的創造者,更是移動與高并發大數據應用新技術的引導者與創新者。我們與Google Flutter/Dart小組密切合作,為社區貢獻了多個高star的項目和大量PR。我們正在積極探索深度學習和視覺技術在互動、交易、社區場景的創新應用。閑魚技術與集團中間件團隊共同打造的FaaS平臺每天支持數以千萬級用戶的高并發訪問場景。
就是現在!客戶端/服務端java/架構/前端/質量工程師面向社會+校園招聘,base杭州阿里巴巴西溪園區,一起做有創想空間的社區產品、做深度頂級的開源項目,一起拓展技術邊界成就極致!
*投喂簡歷給小閑魚→guicai.gxy@alibaba-inc.com
開源項目、峰會直擊、關鍵洞察、深度解讀
請認準閑魚技術
景
在閑魚消息體系中,富文本在 UI 側占了非常大的比重。最近消息部分在整體 Flutter 化,如何解決 Flutter 側富文本問題,成為了項目早期的風險點。
在 Native 中,消息使用了 HTML 協議來承載富文本的解析與展示,由于消息的歷史數據有落庫的特性,我們必須在 Flutter 側兼容這種協議。對于 Flutter,我們是否可以在兼容的基礎上,進行能力的擴充與完善?
當前閑魚也在升級 Flutter 1.12,所以我們不光要在當前版本支持圖文混排,也需要快速遷移到高版本的系統方案。因此我們需要找到一個兼容性高、易遷移的富文本方案。
行業現狀
行業內,對于舊版的 RichText (Flutter 1.7.3 之前)已有了解決方案,詳見玄川:《如何低成本實現Flutter 富文本,看這一篇就夠了!》。但這里并沒有對富文本的整個鏈路的解決思路,且 Flutter 自身的 RichText 也在隨著版本迭代進行演進,我們需要一套完整的演進方案。
事實上,Flutter 1.7.3 開始的 RichText 解決了我們的很多麻煩,它是怎么實現的呢?和舊版的實現有什么區別呢?帶著問題,我們先來分析它的實現原理。
RichText圖文混排原理
Flutter 1.7.3 開始,RichText 不再繼承自 LeafRenderObjectWidget,而是繼承自 MultiChildRenderObjectWidget,從這就很容易看出,RichText 將是一個布局控件,內部可以有多個子控件。
創建過程
如上圖,我們傳給 RichText 的 text 參數為 InlineSpan,TextSpan、WidgetSpan都是其子類。
渲染過程
上圖為 RenderParagraph 內的 performLayout 函數。
概括來說,新版本對比舊版本,底層多了個 _addPlaceholder 能力,用來占位混排的 Widget,并獲取位置信息。
設計思路
我們以 HTML 協議為抓手,不光可以解決普通 HTML 字符串的解析與渲染,也可以對用戶發送的帶閑魚自定義 emoji 的字符串進行能力的擴充。下圖為大致的設計思路:
當前消息展示分為兩種場景,一種為帶有閑魚自定義 emoji 表情的字符串:
你好[微笑],你的寶貝不錯哦[呲牙],包郵嗎?[壞笑][壞笑]
另一種為簡單的 HTML 字符串:
"<fontcolor="#888888">交易全程在閑魚,</font><strong><fontcolor="#F54444">你敢買,我敢賠!</font></strong><fontcolor="#888888">若遇欺詐造成</font><strong><fontcolor="#F54444">錢貨兩失,可獲賠</font></strong><strong><fontcolor="#F54444">最高5000元</font></strong>"
當然,還有最普通的純文本。
對于這三種字符串,服務端并沒有用類型來給我們區分,客戶端拿到的都為字符串。端側該如何處理且高效展示呢?
過程設計成這樣:
流程上,先將閑魚自定義 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 里了。
我們把目光轉向發布和寶貝詳情:
我們后續可能會支持上圖中,發布和寶貝詳情的富文本編輯和展示。對比兩個詳情頁,很明顯能看出,使用富文本的方式,在表達上更加富有沖擊力,買家閱讀起來能很容易抓住賣家想表達的關鍵信息。
可見,未來在富文本的編輯、展示基礎能力統一之后,可以讓更多業務收益。
育知同創前端培訓技術分享:HTML簡介及常用標簽(中)
七、HTML4.0與HTML5.0的規范
–Html4.0的基本規范
?標簽名和屬性名稱不區分大小寫
?HTML標簽不必全部關閉
?屬性值用引號或者不用引號括起來
?標簽必須正確嵌套
?文檔必須擁有一個根元素,所有的XHTML元素必須嵌套于<html>根元素中
–XHTML基本規范
?標簽名和屬性名稱必須小寫
?HTML標簽必須關閉
?屬性值必須用引號括起來
?標簽必須正確嵌套
?文檔必須擁有一個根元素,所有的XHTML元素必須嵌套于<html>根元素中
–Html5的基本規范:對于html4和xhtml的規范都可以并對在基礎上又做了簡化。漸進增強和優雅降級
八、HTML4.0與HTML5.0的區別
D、HTML5新增了一些標簽,也廢棄了一些標簽
新增標簽
?<article>
?<aside>
?<audio>
?<canvas>
?<footer>
?<header>
?<hgroup>
?<section>
?<time>
?<video>
?。。。。
廢棄標簽
a)能用css代替的元素basefont、big、center、font、s、strike、tt、u
b)不再使用frame框架
c)只有部分瀏覽器支持的元素applet、bgsound、blink、marquee等標簽
d)其他被廢除的元素 Rb acronym dir isindex listing xmp nextid plaintex
九、photoshop的基本使用
我們前面了解了一個網站從無到有的過程,那設計師給我們是一個效果圖,我們需要把效果圖用photoshopt(我們這里主要講解的是photoshop)等相關技術把網頁中的圖片切割下來。
Photoshop常用快捷鍵
頁面顯示比例的放大與縮小:Ctrl+加號(放大)、Ctrl+減號(縮小)
臨時抓手工具:空格
標尺的顯示、隱藏: CTRL+R
選擇工具的使用
顯示/隱藏“信息”面板:F8
選擇框的取消:Ctrl+D
單位的設置
參考線的設置
自由變換:Ctrl+T
切片
*請認真填寫需求信息,我們會在24小時內與您取得聯系。