我对Flutter的第一次失望

老孟导读:此文翻译自: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】:
![]() |
![]() |
我对Flutter的第一次失望的更多相关文章
- 关于Flutter初始化流程,我必须告诉你的是...
1. 引言 最近在做性能优化的时候发现,在混合栈开发中,第一次启动Flutter页面的耗时总会是第二次启动Flutter页面耗时的两倍左右,这样给人感觉很不好.分析发现第一次启动Flutter页面会做 ...
- flutter本地环境的安装以及编辑器的配置
由于本文图片比较多,所有都缩小了不少,点击图片就可以放大看到原始图片 使用镜像 cmd打开终端,贴上以下代码,以加入到环境变量中,如果添加失败,可以手动添加 export PUB_HOSTED_URL ...
- 闲鱼Flutter&FaaS云端一体化架构
讲师介绍 国有,闲鱼架构团队负责人.在7月13号落幕的2019年Archsummit峰会上就近一年来闲鱼在Flutter&FaaS一体化项目上的探索和实践进行了分享. 传统Native+Web ...
- Flutter的环境配置以及一些常见问题
flutter & AndroidStudio flutter的下载与配置 flutter是Google推出的基于Dart语言开发的跨平台开源UI框架,能够支持安卓与iOS. flutter框 ...
- Flutter 第一次运行就出现白屏的问题
--enable-software-rendering 解决办法: 顶部菜单找到 run-->Edit Configurations 中加这么一句:
- NOIP2015游记——一次开心又失望的旅行
啊,一年一度的NOIP终于是结束了 以前的大神都有写自己的感受 然而我居然给忘了!!!! 吓得我赶紧来写一份游记 Day.-INF--出发前一个星期 机智的我选择了停课 就是为了OIER这伟大而又光荣 ...
- 团队作业4——第一次项目冲刺(Alpha版本)第五天
天气阴转晴 一.Daily Scrum Meeting照片 二.燃尽图 三.项目进展 1.界面 功能界面已经大致完成 实现判断学生答题正误的界面 2.出题方面 实现错题库的构造 四.困难与问题 1.项 ...
- Android程序员的Flutter学习笔记
作为忠实与较资深的Android汪, 最近抽出了一些时间研究了一下Google的亲儿子Flutter, 尚属皮毛, 只能算是个简单的记录吧. Google自2017年第一次提出Flutter, 到20 ...
- Android Studio集成Flutter
首先Flutter中文网教程地址:https://flutterchina.club/get-started/install/ 1.新建环境变量 变量名:PUB_HOSTED_URL 变量值:http ...
随机推荐
- python 操作元组 列表===python中三大宝刀(字典已经再上一遍 说过)
字典俗称,世界有多大就能装多大 列表俗称,你们决定 元组俗称,可远观而不可亵玩焉 列表的相关操作a=['1','2','3','5','6','7']# print(a[0])# print(a[0: ...
- 无所不能的Embedding 1 - Word2vec模型详解&代码实现
word2vec是google 2013年提出的,从大规模语料中训练词向量的模型,在许多场景中都有应用,信息提取相似度计算等等.也是从word2vec开始,embedding在各个领域的应用开始流行, ...
- 华为云GaussDB(DWS)内存知识点,你知道吗?
前言 在日常数据库的使用中,难免会遇到一些内存问题.此次博文主要向大家分享一些华为云数仓GaussDB(DWS)内存的基本框架以及基本视图的使用,以便遇到内存问题后可以有一个基本的判断. 注意,本篇博 ...
- 【BZOJ2821】作诗 题解(分块+前缀和)
前言:世间还有这么卡常的题…… ------------------ 题目链接 题目大意:给定长度为$n$的序列${a_i}$.有$m$次询问,问$[l,r]$内出现正偶数次的数字有多少个. 这题跟蒲 ...
- JDK11.0.7下载及安装详细教程(win10)
0.背景知识 JRE: Java Runtime Environment JDK:Java Development Kit JRE顾名思义是java运行时环境,包含了java虚拟机,java基础类库. ...
- 关于手机数码圈KOL的一两点感想
复工以来,高峰时段9号线地铁上的人依旧不少,安全距离啥的肯定是不用想了,只是从原来的4G手机换成5G手机以后在某些站能接收到5G信号,我终于能在一些原来根本没信号的站里愉快的刷一刷微博和酷安了. 但是 ...
- 【LeetCode/LintCode 题解】约瑟夫问题 · Joseph Problem
n个人按顺序围成一圈(编号为1~n),从第1个人从1开始报数,报到k的人出列,相邻的下个人重新从1开始报数,报到k的人出列,重复这个过程,直到队伍中只有1个人为止,这就是约瑟夫问题.现在给定n和k,你 ...
- java二进制表示形式与移位操作符
java二进制表示形式 java中数字的二进制表示形式称为"有符号的二进制补码",下面先介绍原码,反码,补码. 编码 计算方法 原码 用最高位表示符号位,'1'表示负号,'0'表示 ...
- C#LeetCode刷题之#171-Excel表列序号(Excel Sheet Column Number)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3852 访问. 给定一个Excel表格中的列名称,返回其相应的列序 ...
- 【原创】Linux虚拟化KVM-Qemu分析(一)
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: KVM版本:5.9 ...

