我对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 ...
随机推荐
- 精讲RestTemplate第2篇-多种底层HTTP客户端类库的切换
本文是精讲RestTemplate第2篇,前篇的blog访问地址如下: 精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用 RestTemplate只是对其他的HTTP客 ...
- MySQL索引结构原理分析
我们在学习MySQL的时候经常会听到索引这个词,大概也知道这是什么,但是深究下去又说不出什么道道来.下面将会比较全面的介绍一下关于索引! 1 索引是什么? 这里用百度百科的一句话来说,在关系数据库中, ...
- tree命令编译使用
有天在linux中使用tree命令时候显示--未找到命令 记下解决过程: wget ftp://mama.indstate.edu/linux/tree/tree-1.6.0.tgz tar xzv ...
- 程序员必须了解!IntelliJ IDEA 2020.2的新增功能
IDEA 因为之前破解过,所以家里的电脑都是19版本的,用的也比较顺手,也就一直懒得去动他,但是,程序猿的好奇心可能真的挺重,猎奇心里,在网上也看到了很多关于2020版本的idea的各种好处,于是,闲 ...
- Codechef July Challenge 2020 Division 1 记录
目录 Missing a Point Chefina and Swaps Doctor Chef Chef and Dragon Dens LCM Constraints Weird Product ...
- 简化RESTful开发,Spring Data REST让你少掉发
1 前言 欢迎访问南瓜慢说 www.pkslow.com获取更多精彩文章! 前言 Springboot + Spring MVC大大简化了Web应用的RESTful开发,而Spring Data RE ...
- adb-使用
1.打印日志 adb logcat -v time > logname.txt adb logcat -v > logname.txt 2.删除手机缓存日志 adb logcat -c 3 ...
- 全面介绍eBPF-概念
全面介绍eBPF-概念 前面介绍了BCC可观测性和BCC网络,但对底层使用的eBPF的介绍相对较少,且官方欠缺对网络方面的介绍.下面对eBPF进行全面介绍. 目录 全面介绍eBPF-概念 BPF概述 ...
- Java 循环语句及流程控制语句
java循环语句while与do-while 一 while循环 while循环语句和选择结构if语句有些相似,都是根据条件判断来决定是否执行大括号内的执行语句. 区别在于,while语句会反复地进行 ...
- C#LeetCode刷题之#232-用栈实现队列(Implement Queue using Stacks)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4108 访问. 使用栈实现队列的下列操作: push(x) -- ...

