最近,有个新闻引起了我的注意,即
Flutter(1.9)的下一
版本已发布 ,它具有许多优点,包括对Web应用程序的早期支持。
在工作中,我正在React React上开发移动应用程序,但出于好奇,我对Flutter颇有兴趣。 对于那些尚不了解的人:在Flutter上,您已经可以创建Android和iOS的应用程序,正在准备发布Web应用程序,还计划支持桌面。
这就是“一环统治一切”。
经过几天的思考之后,我决定尝试使用哪种应用程序,我决定选择一个带有星号的任务-这些破旧的轨道需要什么? 在桌面上摇摆并英勇地克服了困难! 展望未来,我会说几乎没有困难。
切入-关于我如何使用Flutter工具解决通常的React Native程序员任务的故事,以及该技术的总体印象。

考虑到我想“触摸” Flutter的哪些功能,我决定在我的应用程序中应该是:
- 向远程API的请求;
- 屏幕之间的过渡;
- 过渡动画
- 状态管理员-redux或类似的东西。
我不知道如何后端,所以我决定寻找第三方开放API。 结果,我选择了此资源
-XML和JSON,API的CBR课程 。 好了,我终于决定了该应用程序的功能:将有两个屏幕,主要是一个屏幕,以CBR汇率列出货币,当您单击一个列表项时,我们将打开一个包含详细信息的屏幕。
准备工作
由于
flutter create
命令尚不知道如何为Windows / Linux创建项目(当前仅支持Mac,为此请使用
--macos
标志),因此您必须使用
此存储库,其中有一个准备好的示例。 我们克隆存储库,从那里获取
example
文件夹,如有必要,将其重命名并继续在其中工作。
由于仍在开发对桌面平台的支持,因此您仍然需要执行许多操作。 要访问正在开发的功能,请在终端中运行:
flutter channel master flutter upgrade
另外,您需要告诉Flutter它可以使用您的平台:
flutter config --enable-linux-desktop
或
flutter config --enable-macos-desktop
或
flutter config --enable-windows-desktop
如果一切顺利,那么通过运行
flutter doctor
命令,您应该会看到类似的输出:

所以,风景已经准备好了,大厅里的观众们-我们可以开始了。
布局图
React Native之后引起您注意的第一件事是缺少一种特殊的标记语言la JSX。 Flutter迫使您在
Dart中编写标记和业务逻辑。 最初,这很烦人:外观没什么变化,代码看起来很笨拙,甚至这些括号都位于组件的末尾!
例如:

这不是极限! 值得在错误的地方删除一个,并保证为您带来愉快的(没有)消遣。
另外,由于Flutter中样式组件的特殊性,对于大型组件,从编辑器左边缘开始的缩进非常迅速地增加,并且括号的数量也随之关闭。
此功能是在Flutter中,样式是相同的组件(更确切地说是小部件)。
如果在React Native中在
View
连续排列三个按钮,以便它们均匀地分布容器空间,那么对于我来说,为样式中的
View
指定
flexDirection: 'row'
为样式中的按钮添加
flex: 1
足够了,那么Flutter具有一个单独的组件一行,用于在一个行中排列元素,而另一个行用于在整个可用空间中元素的“可扩展性”:
Expanded
。
结果,代替
<View style={{height: 100, width:300, flexDirection: 'row'}}> <Button title='A' style={{flex:1}}> <Button title='B' style={{flex:1}}> <Button title='C' style={{flex:1}}> </View>
我们必须这样写:
Container( height: 100, width: 300, child: Row( children: <Widget>[ Expanded( child: RaisedButton( onPressed: () {}, child: Text('A'), ), ), Expanded( child: RaisedButton( onPressed: () {}, child: Text('B'), ), ), Expanded( child: RaisedButton( onPressed: () {}, child: Text('C'), ), ), ], ), )
比较冗长,不是吗?
或者说,您想向此容器添加带有圆角边缘的框架。 在React Native中,我们只需添加以下样式:
borderRadius: 5, borderWidth: 1, borderColor: '#ccc'
在Flutter中,我们必须在容器参数中添加以下内容:
decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(5)), border: Border.all(width: 1, color: Color(0xffcccccc)) ),
总的来说,起初,我的标记变成了大量的代码,其中的恶魔会折断他的腿。 但是,并非一切都那么糟糕。
首先,当然必须分解大型组件-将其放置在单独的小部件中,或者至少放置在小部件类的方法中。
其次,VS Code中的Flutter插件有很大帮助-在上图中,括号中的注释由插件本身签名(并且它们不可删除),这有助于避免括号引起混淆。 加上自动格式化工具-半小时后,您就会习惯于定期按
Ctrl+Shift+I
来格式化代码。
此外,第二版中Dart语言的语法变得更加令人愉悦,因此到今天结束,我已经很喜欢使用它了。 不寻常? 是的 但不是不愉快的。
API请求
在React Native中,为了从某些API获取数据,我们通常使用
fetch
方法,该方法将
Promise
返回
Promise
我们。
在Flutter中,情况类似。 在查看了文档中的示例之后,我将http包添加到
pubspec.yaml
(来自JS world的
package.json
的类似物),并编写了如下内容:
Future<http.Response> getAnything() { return http.get(URL); }
Future
对象的含义与Promise非常相似,因此此处的所有内容都非常透明。 好吧,对于序列化/反序列化json对象,您可以将模型类的概念与特殊方法
fromJSON
/
toJSON
。 您可以在
文档中阅读有关此内容的更多信息。
屏幕之间的过渡
尽管我正在制作桌面应用程序,但从Flutter的角度来看,它在哪个平台上旋转都没有区别。 好吧,也就是说,就我而言,通常是这样-我不知道。 实际上,启动颤动应用程序的系统窗口与智能手机的屏幕相同。
屏幕之间的转换非常简单:我们创建一个屏幕小部件类,然后使用标准的
Navigator
类。
在最简单的情况下,它可能看起来像这样:
RaisedButton( child: Text('Go to Detail'), onPressed: () { Navigator.of(context).push<void>(MaterialPageRoute(builder: (context) => DetailScreen())); }, )
如果您的应用程序有多个屏幕,则首先准备一个路由字典,然后使用
pushNamed
方法更为合理。 文档中的一个小例子:
class NavigationApp extends StatelessWidget {
另外,您可以准备一个特殊的动画以在屏幕之间切换并编写如下内容:
Navigator.of(context).push<void>(ScaleRoute(page: DetailScreen()));
ScaleRoute
是用于创建过渡动画的特殊类。 这样的动画的很好的例子可以在
这里找到。
国家管理
碰巧我们需要从应用程序的任何部分访问某些数据。 在React Native中,
redux
通常用于这些目的(如果不是最常见的话)。
对于Flutter,有一个
存储库 ,显示了使用各种应用程序架构的示例-Redux,MVC和MVU,甚至是我以前从未听说过的那些。
在这些示例中稍作改动后,我决定停止使用
Provider
。
总的来说,这个想法很简单:我们创建一个
ChangeNotifier
类的特殊类,在其中存储数据,使用此类的方法对其进行更新,并在必要时从那里进行提取。 有关更多详细信息,请参见软件包
文档 。
为此,请将
provider
包添加到
pubspec.yaml
并准备Provider类。 就我而言,它看起来像这样:
import 'package:flutter/material.dart'; import 'package:rates_app/models/rate.dart'; class RateProvider extends ChangeNotifier { Rate currentrate; void setCurrentRate(Rate rate) { this.currentrate = rate; notifyListeners(); } }
这里
Rate
是我的货币模型类(带有
name
,
code
,
value
等字段),
currentrate
是将存储所选货币的字段,
setCurrentRate
是
currentrate
值的方法。
为了将我们的提供程序附加到应用程序,我们更改了应用程序类代码:
@override Widget build(BuildContext context) { return ChangeNotifierProvider( builder: (context) => RateProvider(),
就是这样,现在,如果我们要保存所选的货币,则可以编写如下代码:
Provider.of<RateProvider>(context).setCurrentRate(rate);
如果我们想获取存储的值,则可以这样:
var rate = Provider.of<RateProvider>(context).currentrate;
一切都很透明,没有样板(与Redux不同)。 当然,对于更复杂的应用程序,可能一切都不会那么顺利,但是对于像我的例子那样的纯葡萄酒。
构建应用
从理论上讲,
flutter build <platform>
命令用于构建应用程序。 实际上,当我执行
flutter build linux
命令时,我收到以下消息:

“它没受伤。”我想,
build
文件夹的重量让我感到震惊-287.5 MB-由于我的灵魂很简单,我永远删除了该文件夹。 事实证明-是徒劳的。
删除
build
目录后,项目停止启动。 我无法还原它,所以我从原始示例中复制了它。 它没有帮助-收集器发誓丢失文件。
经过一番研究,结果发现此文件夹中有一个
snapshot_blob.bin.d
文件,显然,其中写入了项目中使用的所有文件的路径。 我添加了缺少的路径,并且有效。
因此,Flutter目前不知道如何为桌面准备发行版本。 无论如何,对于Linux。
总的来说,如果您不注意这一点,该应用程序就会变成我想要的样子
红利
我们传递给承诺的奖金。
即使在编写应用程序的阶段,我仍然希望检查将其移植到其他平台有多困难。 让我们从手机开始。
当然,有一种不太野蛮的方法,但是我决定最短的路径是直接的。 因此,我只是创建了一个新的Flutter项目,将
pubspec.yaml
文件,
assets
,
fonts
和
lib
目录转移到其中,并将该行添加到
AndroidManifest.xml
:
<uses-permission android:name="android.permission.INTERNET" />
该应用程序以半踢开始,我知道了
一开始,我不得不修改网络。 我不知道如何创建Web项目,因此我使用了Internet上的说明,由于某些原因,该说明不起作用。 我已经想吐了,但是碰到了
这本手册。
结果,一切都变得尽可能简单-所需要的只是启用对Web应用程序的支持。 挤压手册:
flutter channel master flutter upgrade flutter config --enable-web cd <into project directory> flutter create . flutter run -d chrome
然后,我以同样的野蛮方式将必要的文件传输到该项目,并收到
总体印象
最初,与Flutter合作并不寻常,我一直试图使用React Native的常规方法,但这样做会造成干扰。 另外,dart代码的一些冗余也很烦人。
当我握了一下手(和锥体)后,我开始看到Flutter比React Native的优势。 我会列出一些。
语言 。 Dart是完全可理解且不错的语言,具有强大的静态类型。 使用JavaScript后,就像呼吸了一口新鲜空气。 我不再担心我的代码会在运行时中断,这是一种令人愉快的感觉。 有人可能会说有Flow和TypeScript,但事实并非如此-在我们的项目中,我们同时使用了两者,而其他东西总是在某个地方出现问题。 当我用React Native编写代码时,我不禁觉得自己的代码在火柴棍道具上,随时可能中断。 使用Flutter,我忘了这种感觉,如果价格是代码冗余,那么我准备付款。
平台 。 在React Native中,您使用本机组件,这通常很好。 但是正因为如此,您有时必须编写特定于平台的代码,并捕获特定于每个平台的错误。 它可能令人难以置信。 使用Flutter,您可以像噩梦一样忘记这些问题(尽管在大型应用程序中情况可能并不那么顺利)。
环境 。 在React Native中使用环境时,一切都是令人悲伤的。 vscode插件会不断脱落,调试器可以吞噬16个可操作的组件和70个可互换的组件,紧密挂起系统(根据个人经验),以及最常见的错误纠正方案:“删除node_modules,再次安装软件包,然后尝试重新启动几次。” 这通常会有所帮助,但是太过分了! 事实并非如此,并非如此。
此外,您将必须定期运行AndroidStudio和Xcode,因为其中的某些功能仅通过这种方式放置(公平地说,随着RN 0.60的发布,情况会变得更好)。
在这种背景下,vscode的官方Flutter插件看起来非常不错。 代码提示使您无需了解文档即可熟悉平台,自动格式化可解决编码风格,常规调试器等问题。
通常,它看起来像是一种更成熟的工具。
跨平台 。 React Native奉行“学习一次,到处编写”的原则-学习后,您可以为不同的平台编写代码。 的确,在每个平台下,您都会遇到特定的问题。 但这也许仅仅是React Native不成熟的结果-目前,最新的稳定版本是0.61。 也许随着1.0版的发布,这些问题中的大多数都会消失。
Flutter方法更像一次编写,可在任何地方编译。 即使目前还不能准备生产台式机,Web也处于Alpha状态,但一切都已实现。 对于所有平台拥有单一代码库的能力是一个很强的理由。
当然,Flutter也不是没有缺陷,但是使用它的一些经验不能使我识别出它们。 因此,如果您要进行更客观的评估-请随时轻视新奇效果。
总的来说,应该注意的是,尽管他有成长的空间,但Flutter大多留下了积极的感觉。 在下一个项目中,我将更愿意开始而不是在React Native上开始。
该项目的源代码可以在
GitHub上
找到 。
附言:我借此机会祝贺过去的教师节活动中的所有参加者。