[Flutter翻译]我对Flutter的第一次失望

3,325 阅读8分钟

原文地址:medium.com/@suragch/my…

原文作者:medium.com/@suragch

发布时间:2019年7月10日 - 7分钟阅读

悲哀

我喜欢Flutter。我喜欢开发一次,让代码在Android和iOS上同时运行。我喜欢这样可以节省很多时间。我喜欢现在做一个web开发者,不需要做任何额外的工作。我喜欢热重载。我喜欢通过将小部件组成布局来快速构建用户界面。我喜欢做一个ListView更简单。我喜欢状态管理。(好吧,关于这一点我只是开个玩笑。但我可以接受。) 我喜欢Dart。我喜欢Futures和async/await比Android AsyncTasks甚至iOS Dispatch Queues简单得多。

但在花了两周时间研究Flutter如何渲染文本之后,我对我们得到的工具感到失望。

我们已经被告知

Flutter的分层架构让你可以控制屏幕上的每一个像素。

这显然不适用于用于绘制文本的像素。

Flutter中的低级文本功能

Flutter使用Skia、Harfbuzz、Minikin和ICU的组合使用名为LibTxt的库来渲染文本。开发者在使用Text widget或TextSpan甚至是TextPainter时都会间接使用它。在我们可用的最底层,也就是dart:ui中,有一个Paragraph类,它是使用ParagraphBuilder构建的。这些类基本上只是底层LibTxt引擎的包装器。几乎所有的工作都是由这个引擎完成的,只有很少的部分暴露在dart:ui中。

Paragraph类给我们提供了以下控件:

  • Size: 我可以得到整个渲染段落的宽度和高度,可能是单行或多行。
  • 基线的距离(只针对第一行)。
  • 文本是否溢出了maxLines变量。
  • 文本运行框的大小和相对位置(即bidi文本的行或节)。下面是一个例子。

图片来自这里

  • 最接近某个像素位置的文本字符索引。在上面的例子中,像素(1,1)将对应于字符串中的索引0,也就是 "我的文本行 "的字母 "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,但通过使用StaticLayoutCanvasPaint类,你可以获得低级别的控件来完成我上面列出的所有事情。这里只是众多可用选项中的几个:

我在iOS上没有那么多低级的文字绘制经验(因为我以为只要学会在Flutter中做所有的事情就可以了),但是Core Text有一套丰富的工具。

Flutter repo样式指南留着:

对于针对多个平台的SDK来说......提供能在所有目标平台上工作的API是很常见的。不幸的是,这通常意味着一个平台或另一个平台所特有的功能是不可用的。

对于Flutter来说,我们希望通过明确的目标来避免这种情况,即为每个平台单独开发的最佳方式。我们的跨平台使用能力是次要的,而不是在每个平台上使用的能力。(强调是后加的)

目前,对于我们这些需要在应用中进行低级文本渲染的人来说,Flutter并不是最好的开发平台。

使用案例

你可能会说,Flutter已经提供了Text和RichText部件。这是真的,它们非常好。它们可以满足99.9%的开发者的需求。但也有一些用例需要访问低级别的文本渲染工具。

蒙古语

我的用例是布局和渲染传统的蒙古文,它是垂直书写的,从左到右包线。英文是横着写的,但中日韩和表情符号字符应该保持正常方向。

蒙古文排版。图片来自这里

有一些使用小组件组成的 "解决方案",但是当你加上对文本样式的需求(比如通过在文本的右边画一条垂直线来 "下划线"),一个更强大的解决方案将是手工完成所有的文本测量、布局和绘画。我已经在这里开始研究了。

中日韩语言

中文、日文和韩文也可以按不同的垂直方向排列。和蒙古语一样,对于一次性的情况,有一些变通的方法,但是对于普通的使用,一个渲染包会更有帮助。阅读这里可以了解到更详细的需求描述。

垂直的中日韩文字布局。图片来自这里

Flutter只支持支持从右到左和从左到右的布局。垂直布局不支持(也不会😞)。我不怪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/flu…

为了将这个问题分解成更小的部分,我添加了以下具体的功能请求。如果你也需要这些功能,请加注和/或评论。

我还没有提交任何具体的bug报告,与许多小段落对象的测量和绘画的效率有关。原因是我自己还没有注意到任何性能问题。如果你遇到了这样的问题,请创建一个详细的GitHub问题并@我。我会把它链接到这里。


通过( www.DeepL.com/Translator )(免费版)翻译