我對Flutter的第一次失望

老孟導讀:此文翻譯自://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類獲得低級控制項來執行上面列出的所有操作。以下是可用的眾多選項中的幾個:

我在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團隊了解您的需求與自定義文本呈現相關的好時機。請參閱以下部分。

你可以做什麼

即使以下問題當前已關閉(儘管尚未解決),如果您還需要執行自定義文本呈現,請繼續對其進行投票並在其上留下評論。

地址://github.com/flutter/flutter/issues/35994

為了將問題分解為更小的部分,我添加了以下特定功能要求。如果您還需要它們,請投票和/或評論。

我尚未提交任何具體的錯誤報告,但與許多小型Paragraph對象的測量和繪畫效率有關。原因是我自己沒有發現任何性能問題。如果您遇到過此類問題,請創建一個詳細的GitHub問題,並@suragch me。我會在這裡鏈接到它。

交流

老孟Flutter部落格地址(330個控制項用法)://laomengit.com

歡迎加入Flutter交流群(微信:laomengit)、關注公眾號【老孟Flutter】:

Tags: