
老孟導讀:此文翻譯自:https://medium.com/@suragch/my-first-disappointment-with-flutter-5f6967ba78bf
我喜歡Flutter,我喜歡開發一次并讓代碼在Android和iOS上運行,我喜歡節省多少時間,我喜歡現在成為一名Web開發人員,而無需做任何額外的作業,我喜歡hot reload,我喜歡通過將小部件組合到布局中來快速構建UI,我喜歡制作ListView簡單得多,我喜歡狀態管理, (好吧,只是在開玩笑,但是我可以應付,)我喜歡Dart,我喜歡Future和async / await比Android AsyncTasks甚至iOS Dispatch Queue容易得多,
但是,在花了最后兩周的時間研究Flutter如何呈現文本后,我對使用的工具感到失望,
我們被告知:
Flutter的分層體系結構使您可以控制螢屏上的每個像素,
這顯然不適用于用于繪制文本的像素,
Flutter中的低級文字功能
Flutter使用名為LibTxt的庫結合使用Skia,Hafbuzz,Minikin和ICU來呈現文本,開發人員在使用Text小部件或TextSpan甚至是TextPainter時間接使用它,在最低級別上,我們可以使用dart:iu,它是使用ParagraphBuilder構建的Paragraph類,這些類基本上只是底層LibTxt引擎的包裝器,幾乎所有作業都由此引擎完成,而在dart:ui中幾乎沒有暴露,
Paragraph類為我們提供了以下控制:
- Size:我可以獲取整個渲染段落的寬度和高度,它可以是單行或多行,
- 距基線的距離(僅對于第一行)
- 文本是否溢位了maxLines變數,
- 文本框的大小和相對位置,這是一個例子:

- 最接近某個像素位置的文本字符索引,在上面的示例中,像素(1、1)對應于字串中的索引0,即“My text line.”的字母“ M”,
- 字串中某些字符偏移的單詞邊界,
隨后的更新也為我們提供了LineMetrics,它為每行提供了許多詳細資訊:
class LineMetrics {
final bool hardBreak;
final double ascent;
final double descent;
final double unscaledAscent;
final double height;
final double width;
final double left;
final double baseline;
final int lineNumber;
}

但是,我們沒有得到:
- 一種在文本框中獲取實際文本的方法,
- 一種控制文本布局方式的方法,
- 一種在路徑上繪制文本的方法,
- 一種無需繪制整個段落即可測量和繪制短文本的方法,
- 一種從文本字串獲取換行位置的方法
與Android和iOS的比較
在Android中,盡管大多數人會使用TextView,但是您可以通過使用StaticLayout,Canvas和Paint類獲得低級控制元件來執行上面列出的所有操作,以下是可用的眾多選項中的幾個:
- [Canvas.drawTextOnPath](https://developer.android.com/reference/android/graphics/Canvas.html#drawTextOnPath(java.lang.String, android.graphics.Path, float, float, android.graphics.Paint))
- [Canvas.drawTextRun](https://developer.android.com/reference/android/graphics/Canvas.html#drawTextRun(char[], int, int, int, int, float, float, boolean, android.graphics.Paint))
- Paint.getFontMetrics
- [Paint.measureText](https://developer.android.com/reference/android/graphics/Paint.html#measureText(java.lang.String, int, int))
我在iOS上沒有那么低級的文字繪制經驗(因為我認為我只會學習在Flutter中做所有事情),但是Core Text具有豐富的工具集,
Flutter 指南中如此說:
以多個平臺為目標的SDK是很常見的……提供可在所有目標平臺上運行的API,不幸的是,這通常意味著一個平臺或另一個平臺獨有的功能不可用,
對于Flutter,我們希望通過明確地成為每個平臺的最佳開發方式來避免這種情況,我們在跨平臺上使用的能力僅次于我們在每個平臺上使用的能力, (添加了重點)
當前,對于需要在應用程式中進行低級文本渲染的我們當中,Flutter并不是最好的開發平臺,
用例
您可能會說Flutter已經提供了Text和RichText小部件,是的,他們非常好,他們將滿足99.9%的開發人員的需求,但是,存在使用較低級別的文本呈現工具的用例,
蒙文
我的用例是布局并渲染傳統的蒙古文字,該文字垂直書寫,并從左到右換行,英語是側身書寫,但CJK和表情符號字符應保持其正常方向,

有一些使用小部件組合的“解決方案”,但是當您添加文本樣式的需要時(例如通過在文本的右側繪制一條垂直線來“下劃線”),一種更可靠的解決方案是處理所有文本手工測量,布置和繪畫,我已經開始在這里作業了,
中文,日文和韓文
中文,日文和韓文也可以按各種垂直方向進行布局,像蒙古語一樣,有一種解決方法,可以解決一次性情況,但對于常用用法,渲染包會更有幫助,閱讀此內容以更詳細地描述需求,

Flutter僅支持支持從右到左和從左到右的布局,不支持(也不支持??)垂直布局,我不會對此表示懷疑,有很多作業,但是我希望他們會給我們更多工具來自己做,
藝術文字
進行文字繪畫的應用程式也將從對文字繪畫工具的低級別訪問中受益,

用文本填充非矩形形狀
為了使文本適合非矩形的內容,您必須進行大量測量,換行在哪里是另一個難題,

文字圍繞排除路徑流動
這在iOS中可用,但在Flutter中不可用,而且沒有簡單的方法可以自己實作,

結論
我并不是想說服任何人不要使用Flutter,我還是很喜歡我再也不想回到為不同平臺構建同一應用程式的多次了,
在撰寫本文時,我希望有人會說:“不,你錯了,如果您這樣做,那么您將可以使用低級文本呈現工具,”不過,我對此并沒有寄予太大希望,因為Flutter的主要開發人員之一對此表示:
如果您想要“真實的”垂直文本,并帶有強調標記,ruby和行內水平的bidi文本以及所有內容,那么我能提供的最好的辦法是,您可以嘗試使用我們提供的較差的原語撰寫一個程式包來支持此操作,但是可能不會是令人滿意的體驗,
我真正希望的是Flutter小組將為我們提供與UI布局級別一樣的文本自由,添加一個dart:ui類以暴露更多LibTxt庫并不是特別困難,的確,維護起來會更多,開發人員可能偶爾會用它來撰寫效率低下的代碼,但我認為自由值得付出代價,使Flutter成為使用任何語言開發任何平臺的最佳方式,
2020年2月更新
當我最初發布這篇文章時,Flutter團隊迅速做出了回應(請參閱下面的評論),許多作業正在完成(如GitHub問題所記錄,謝謝Gary Qian),并且希望可能會有一些重大的改進,但是,盡管遭到了強烈支持,但該GitHub問題最終因其作業量過多而被關閉,
我最近得知,正在完成用Skia SkParagraph模塊替換LibTxt的作業,這聽起來很令人興奮,但是我還不知道細節,您可以在此處跟蹤進度,由于這是一項重大更改,因此現在是讓Flutter團隊了解您的需求與自定義文本呈現相關的好時機,請參閱以下部分,
你可以做什么
即使以下問題當前已關閉(盡管尚未解決),如果您還需要執行自定義文本呈現,請繼續對其進行投票并在其上留下評論,
地址:https://github.com/flutter/flutter/issues/35994
為了將問題分解為更小的部分,我添加了以下特定功能要求,如果您還需要它們,請投票和/或評論,
- Need a line/word breaker for custom text rendering #50171
- Need to find how much of a long word could fit in one line before an unnatural line break #51258
我尚未提交任何具體的錯誤報告,但與許多小型Paragraph物件的測量和繪畫效率有關,原因是我自己沒有發現任何性能問題,如果您遇到過此類問題,請創建一個詳細的GitHub問題,并@suragch me,我會在這里鏈接到它,
交流
老孟Flutter博客地址(330個控制元件用法):http://laomengit.com
歡迎加入Flutter交流群(微信:laomengit)、關注公眾號【老孟Flutter】:
![]() |
![]() |
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/303.html
標籤:Dart


