原文作者:medium.com/@ecspike
发布时间:2019年7月15日
几个月前,当我重新沉浸在Flutter中时,我想:"我真的很喜欢Flutter,但它的声明性有时会让我对Widget的位置感到困惑,我想知道是否有办法让它不那么混乱。" 我有一个教学背景,所以对于一个实验性的学习项目来说,在没有代码的情况下进行编码似乎是成熟的。
AppInventor引起了我的兴趣,直到我看到它的代码和互动使用了一个完全非标准的库。尽管这是一个实验,但我希望它能以典型的Flutter应用中出现的代码为基础。对AppInventor的研究确实让我了解到了Blockly,这是一个可以用互锁的构件生成代码的库。
Blockly被用于许多教育和业余环境,如Scratch、micro:bit,甚至一些Arduino应用程序。
谷歌开发者:Blockly
Blockly可以生成JavaScript、Python、PHP、Lua和Dart代码。Blockly可以扩展到其他语言,但它已经能够理解Dart,尽管需要进行一些调整,这是一个很大的胜利。
有许多内置的块用于常见的结构,如条件语句、循环、各种数字运算、列表和函数。除此以外,你可以使用Blockly开发工具创建自己的块。
Blockly开发工具:用于创建新块
开发者工具为您提供了确定输入/输出的选项,以及块如何与其他块连接。生成器存根是该块在最终代码中的表现方式。
Flutter Blockly组件
我从一组小的Widget组件开始,最初试图实现Scaffold的内部核心,然后向外扩展,包括MaterialApp,甚至无状态和有状态的Widget。
- 材料应用
- 棚架
- AppBar
- 行
- 列
- 列表视图
- 图标
- 文本
- 占位符
- 浮动的行动按钮/凸起的按钮
我们的重点不是要实现每一个小部件,而是要实现足够多的小部件,以提供一些自定义的功能,并保持应用程序的流程易于阅读。
无状态小部件和有状态小部件
StatelessWidget和StatefulWidget是第一个大挑战。首先,它们需要成为类,而Blockly并不是为适应这些类而建立的,而是向更多的功能风格看齐。其次,函数和变量的声明也默认为全局的。这对于一个主函数来说是很好的,但对于build(BuildContext context)或任何需要的状态变量来说就不是那么回事了。 对于一个无状态的Widget来说,建立一个组件来模拟一个类并不是太困难。这只是将一个小部件块分配给build属性,并将其推断为一个适当的build函数。
带有一列文本小部件的无状态小部件
一个带有一列文本部件的无状态部件的生成代码
有状态的小部件就有点棘手了。变量需要住在从State派生的类里面。在类内嵌入变量需要一个小黑客:创建一个新的块,接受原始代码输入。这是一个小小的误用,因为任何Blockly都不知道以这种方式创建的任何变量。你失去了在更大的块中使用它们的能力。曾经的原始代码,永远是原始代码。
用Blockly块表示的一个有状态的widget
从StatefulWidget和原始代码块生成的代码
另一个令人头疼的问题是setState。很自然地,我为它创建了一个块,但是如果你把这个块放在一个函数中,它就会默认为全局,你会得到错误,因为它不是一个StatefulWidget。 这就是黑客二号的来源。setState块可以接受原始代码,并且可以直接分配给按钮的onPressed。
代表StatefulWidget和State类的块,为Counter App提供setState。
就这样,我不用一行代码就能做出一个有状态的Hello World(计数器)应用程序。好吧,严格来说,是3行代码。
下面是一段从头到尾的视频(没有音频)。空的MaterialApp和Scaffold实例已经创建,flutter运行已经开始,并指向Flutter项目,将接收来自Web应用的更新。类似的流程也可以用Flutter Web来实现,但是一些小部件不能1:1地从移动端映射到Web端。
这里是完成的应用程序在块中的样子。
计数器应用程序在块中的完整表示
你可以在Github上查看这些代码。
特别感谢 Lara Martín 的意见,以证实这个想法并不完全奇怪,并感谢 Nate Ebel 为其校对和提供反馈。