黎平门户网
国内新闻 当前位置:首页 > 国内新闻 > 正文

不用掉一根头发!用 Flutter + Dart 快速构建一款绝美移动 App

原标题:不要掉一根头发!使用飞镖快速创建一个漂亮的移动应用

author | Wojciech Kuroczycki

translator |弯月形

product | CSDN(ID: CSDNNews)

如今,与前端或移动相关的新框架层出不穷。所有从事网络开发的人都应该熟悉各种新方法和复杂问题的轻量级解决方案。我们不再被现成技术的缺乏所困扰。相反,我们经常感到头痛,因为我们不知道选择哪种技术。

最近,我碰巧发现了颤振,所以我决定愉快地尝试一下,看看这项技术能否成为一个强有力的竞争对手,或者甚至作为一种解决方案,让我在困境中看到新的希望。“扑扑”是谷歌的移动应用用户界面软件。它使用飞镖虚拟机(同样由谷歌生产,专门针对用户界面优化)来帮助我们开发移动设备和桌面设备。Dart本身也可以用于网络开发,甚至与我们非常熟悉的Angular框架结合使用。

Flump可以通过AoT(高级)编译编译成本机代码,以使应用程序以最高的速度运行而不会有太多的开销。

对于开发人员来说,颤振提供了实时编译器和热过载函数。我们可以在不丢失现有状态的情况下修改应用程序,这非常实用,因为在复杂的函数中修改一个隐藏的用户界面非常麻烦,并且所有从事用户界面工作的人都知道,每次找到要修改的用户界面都要花费很多精力。

当然,SDK的一个重要部分是控制库。由于颤振位于安卓和iOS开发,我们可以选择使用材料(谷歌安卓)或库比蒂诺(苹果iOS)控制集。这是否意味着当应用程序部署在安卓或iOS手机上时,它会改变外观,使两者看起来都像本地的?事实并非如此。您可以同时使用任一库或两者,但没有统一的用户界面切换功能。当然,您可以手动完成。我不是说不推荐这样做。但是,请记住,这个功能需要管理两个不同的布局控件,这将很快变得混乱,所以应该小心使用这个方法。

默认情况下,颤振中的一切都是一个小部件。如果你有过使用Angular 2的经验,你可以把wdiget看作一个更强大的组件,应该是一个非常熟悉的概念。默认情况下,此基本类型包括定义外观的构建方法,并且还可以基于传递的参数和上下文自定义外观。小部件可以是无状态的或有状态的。无状态小部件大多是静态的,不会在生命周期中经历任何重大变化。另一方面,有状态的小部件在每次被触发时都会被构建(例如,当被监控的变量改变时,用户执行特定的操作,比如点击)。

颤振是反应式编程(类似于反应式),这意味着没有默认的连续刷新周期(如角度)。相反,一旦执行了一个键操作,用户界面或其一部分(例如一个小部件)将根据状态的变化被重新绘制。

我提到Dart已经被极大地优化来处理用户界面,但是这意味着什么呢?在Flout中,优化的Dart支持丰富的集合处理、基于隔离的并发和未来的异步等待。基本上,这个软件开发工具包的目的是建立商业,而不是游戏。虽然我们不能假设人们不会尝试用飞腾来制作游戏,但即使是2D游戏引擎也已经出现了。但我想说的是,这个应用程序模型似乎非常适合这组特定的功能,这也是我决定探索的角度。

Risk

尽管以上所有这些听起来都不错,但也有一些缺点。

首先,颤振仍然是一个处于婴儿期的SDK。尽管就年龄而言这是正常的,但应该指出的是,阿尔法于2017年5月发布,而1.0直到2018年12月才发布。这意味着在写这篇文章的时候,旋舞只有一岁。后果是什么?颤振的社区已经很大了,但它无法与当前的主流技术相比。这将影响我们对一些常见问题的解决方案的搜索,并可能经历许多失败,需要额外的努力和仔细阅读规范。然而,颤振的文件是健全的,社区是不断发展的,所以我们可以认为颤振在其发展没有明显的缺陷。

其次,飞镖和飞镖都来自谷歌(这可以被视为一个劣势和优势)。好消息是谷歌是一个技术巨人。如果他们想维持它,他们有足够的资源和人力。然而,缺点是,尽管众所周知谷歌将引入非常实用的技术和服务,但它可能随时被淘汰。颤振也面临着这样的风险,但它不太可能在不久的将来发生,甚至在未来几年也不会发生。因此,尽管这是一种风险,但任何新技术都有同样的风险,每一种技术都有这样的经历。

你使用什么工具?

我们可以使用最常见的编程集成开发环境(安卓系统、智能设计、甚至是支持旋舞的可视化工作室代码插件)来开发旋舞,这意味着大多数开发人员不必离开熟悉的环境。就我而言,我最近一直从事面向网络的工作,所以我选择了VS代码,但这不会对开发产生任何影响,因为文本文件毕竟还是文本文件。我选择的平台是安卓(我选择这个平台是因为我既没有苹果手机,也没有苹果电脑),所以看起来我还是会安装安卓工作室,因为安卓工作室提供虚拟机。

除了集成开发环境之外,还有一个监控应用程序性能的套件颤振/飞镖开发工具,以及一些调试工具,如颤振浏览器,类似于网络工具。在研究应用程序的性能瓶颈时,实时资源监视器非常有用,分层查看器可以发现困扰许多应用程序和网站用户界面的冗余嵌套。

入门:“你好,世界”

有什么比编写一个移动应用程序来管理保险单更令人兴奋的吗?请注意,我可能会尝试用不同的方式开发一些函数,这可能会导致代码不一致。该应用程序包含一些解决常见问题的想法和示例。由个人来判断哪个更好,哪个更差。

应用程序的简单概述:

“主页”屏幕显示购买策略的摘要

创建策略

通过向导创建策略

策略可以是不同的类型

保险主题可以是不同的类型

用户需要帐户(不能匿名使用)

应用程序是一个“轻量级客户端”所有的字典、数据和操作都存储在服务器上

请求/响应的主要格式是JSON

我们通过模拟来模拟应用程序接口。在集成开发环境中,我选择VS代码,设备由安卓模拟器提供(我选择Nexus 6 API 28)。首先,我根据颤振项目官方网站上提供的官方指南创建了一个空白应用程序,然后我创建了颤振项目的准系统。我个人创建了如图1所示的结构。请点击此处获取完整的应用程序代码(我建议您参考本文来查看它)。

[图1]初始阶段的项目

视图项目基础

pubspec.yaml文件包含项目依赖关系、资源文件和版本号,这非常简单明了。此外,文档还包含许多说明,但我们不会修改这些说明,至少不会经常修改。对我们来说最重要的是lib文件夹,因为它保存了应用程序的起始文件main.dart文件和其中的主要方法。这是应用程序的入口点,任何代码都不能超过这个点。好了,该搭棚了。

主页是应用程序的默认页面和默认路由。我们将在主页上显示一系列政策。因此,通过我们的api获取字典绝对是合适的。我构建了一个单独的服务,在应用程序启动之前调用API服务并获取字典数据,这样数据就可以在应用程序中的任何地方使用。这个字典叫做公共数据,它的API服务是DictionariesService。两者都位于lib/services文件夹中。我还添加了一个公共帮助服务(名为Helper),它提供了默认填充和公共转换等功能。

[图2]公共数据

CommonData是一个具有内部构造函数的单个实例,该构造函数在其静态字段之一中存储其唯一实例。commonData类定义不会在应用程序中的任何地方使用,而只会在此文件中用于声明CommonData实例。Get方法返回未来,这实际上是一个承诺。这意味着我们可以使用等待等。返回结果,并在一切就绪时继续初始化。然后(…)尽快返回。我们希望初始化在收到响应后完成,所以我们使用wait。稍后我们将介绍DictionaryService.get

的实现。经过一些研究,我发现在绘制用户界面之前运行commonData.initialize非常简单,所以我们把它放在main中(如图3所示)。

[图3]运行应用程序前初始化commonData

命令。这样,无论应用程序在哪里,我们都可以确定commonData已经初始化,因为应用程序本身是在初始化完成后执行的。这种解决方案在许多情况下都很有用,例如服务器存储的应用程序配置文件或主题、数据分段、应用程序设置等。对于异步操作,我们应该在主页屏幕上处理它,因为我们可以在主页屏幕上显示加载进度条。这可以防止用户在应用程序启动时看到空白屏幕,然后怀疑应用程序是否崩溃。因此,如果我们必须在应用程序正常启动之前做一些事情,最好是执行可预测和可忽略的操作,或者创建一个单独的“加载”屏幕并显示一些动画和显式的“加载”消息,以便用户可以安全地等待操作执行,并在完成操作后返回到主页。这种“尴尬的预载”将作为UX的负面例子留在这里。

接下来,让我们看看main下面的MyApp类。它的主体是重写build(BuildContext)方法,每次重绘MyApp小部件时都会调用这个方法。我们的应用程序有多个屏幕:主页和保单创建向导的五个步骤(保单类型、产品、保险范围、投保人和被保险对象),因此我仔细研究了相关主题(如图4所示)。

[图4]颤振应用的导航研究

导航在颤振中被称为“路由”。我已经根据教程创建了一些路由(如图5所示)。默认初始路由(我的主页小部件)和五个向导步骤。我们是否需要访问构建上下文还有待观察,但是把它放在这里没有坏处。

[图5]材料设计中的颤振是颤振应用的基本途径。值得一提的是,由于我们的应用程序使用了材质控制集,并且是一个材质应用的实例,因此我们可以根据材质设计原则快速修改外观。主题数据类包含“材料设计主题的颜色和布局数据”。可以通过应用程序中的静态方法Theme.of(构建上下文)来访问主题数据,并且可以更改其各种属性来更改主题提供的默认值。现在,我们只需要设置primarySwatch(应用程序的主色和各种亮度的颜色)和重音颜色(也是各种亮度的颜色组合,是应用程序的辅助颜色)。

如果我们使用主题的默认值和/或生成值(我们应该尽最大努力),最终的用户界面应该不会太差。如果我们不想使用默认颜色,我们可以定制颜色(如图6所示)。然而,这需要大量的工作(除非客户提供风格指导),我不想破坏美学,所以遵循简单的方法。互联网上有无数的材料颜色样本生成器。如果你想提供“基本”颜色,你可以生成一个。此外,还有一个错误颜色设置,但是作为一个涉足用户界面/UX多年的人,我建议您小心使用这个设置,因为标准红色是错误指示的行业标准。即使允许修改配色方案,也应尽可能避免。最多,只需要稍微修改亮度。

这个过程也可以用来测试“热过载”:试着改变主题颜色,保存它,然后你可以立即看到应用程序中的变化。我对这个功能非常满意。

[图6]自定义颜色示例

主页基本上是显示每个政策的列表。每个列表项都可以展开以显示策略的详细信息,并且还有一个创建新策略的选项。因此,每个列表项都应该是有状态的,因为列表项的外观会有很大的变化,但是整个页面可能是无状态的。主页显示可变长度列表,但其元素和值在其生命周期内不会改变。请注意,如果我们不将每个列表项分成单独的小部件(而是在一个类中处理所有东西),那么页面必须是有状态的。

[图7]我的主页数据初始化

让我们从路由中的数据开始(图7)。每当您导航到“/”时,都会执行此处的逻辑。在这种情况下,这是非常方便的,因为每次我们显示主页屏幕,我们将有最新的用户帐户数据和已经创建的策略。这样,我们就解决了将来会遇到的问题:如何在完成指南后刷新主页。我们只需要往回走。

在我的主页中,你可以看到一些用户界面的定义。页面的根名称是脚手架,它负责设置应用程序栏、操作按钮、文档体和各种其他选项。事实上,这是常见的移动应用程序模板。未定义的部分将被省略。这里的应用栏是最小设置。有一个浮动按钮来启动新策略向导。背景颜色已经链接到当前主题的背景颜色(如果我们想改变颜色,我们需要保持一致性)。当然,还有主体。

如前所述,这些策略被打包在未来,这意味着它们还不能传输到列表视图。这就是FutureBuilder的目的:事实上,它是一个可以根据Future的内部状态返回内容的小部件。我们可以使用AsyncSnapshot变量来返回不同的小部件,这取决于未来是完整的还是仍在进行中的,或者包含错误等等。

对我们来说,如果完成,返回一个列表视图,否则返回一个非常标准的负载指示器。最好将所有可能的错误处理打包到Helper类中的一个公共方法中,该方法可以接受snapshot.connectionState并输出一些公共错误信息。将来有许多方法可以解决这些错误,但是为了简洁起见,我没有在这里使用它们。因此,未来只能是两种状态之一:完成或加载。

[图8] FutureBuilder

再次查看HomepageTile小部件。这是我们第一个有状态的用户界面。每个有状态的小部件包含一个小部件声明(图9)和它的状态,状态是最神奇的部分。

[图9]有状态小部件

小部件的用户界面是由状态中的构建方法定义的。因此,每次调用setState(fn)时,都会重建框架,并用新的属性值重新执行build(BuildContext)方法。在这里,我使用_expanded字段的值作为条件来决定是返回_ buildmaximitile小部件还是返回更详细的_ buildmaximitile小部件。当然,这可能只是一个简单的条件赋值问题,但是我们可以用动画交叉渐变小部件来美化它。

它的功能就像它的名字一样:根据交叉渐变状态(图10),两个子组件淡入淡出。由于每个setState调用都会重建小部件,因此也可以在两个以上的状态之间切换,但是这种用法很少见,因为通过一定次数的点击进入一个状态听起来有点像戏弄用户或玩捉迷藏游戏。除非你有强烈的视觉暗示,否则不要这样做。

[图10]动画交互界面

现在我们知道如何创建一个主页,并使用通用列表项来显示用户的策略。接下来,让我们演示如何向应用程序提供来自模拟API的数据。我们打开了字典服务(图11)。

[图11]dictionarieservice

可以看到get函数被标记为异步,这意味着它的返回值将在未来被包装,并以类似于承诺的方式处理。Http客户端异步执行命令,然后提供响应结果、状态代码等。接下来,我们将JSON(其类型默认为Map)映射到DTO对象。因为这些是字典,所以我为它们创建了映射,这样在显示对应于代码的名称时就不必遍历所有元素(只需写下这个:公共数据)。

让我们看看DTO。没有公认的方法将json转换成对象,但幸运的是我们可以使用许多插件。我在这里使用了json_annotation(它被用来监控启动(颤振包发布运行构建运行观察)来找到

JsonSerializable标签并创建一个映射函数,如图12-13所示。

[图12] policy.dart-DTO类

[图13]policy . g . dart-由json_annotation生成

这极大地简化了工作,并提供了一种非常方便的方式将类映射到json。

Wizard

每个成功的商业应用程序的两个基本部分是表单和验证。让我们看看我们要做的功能和策略指南的代码。前两个步骤(1_newPolicyType,2 _ newpolicytype)是非常标准的事情,到处都可以看到,这里就不再重复了。如果您想了解如何使用异步计算来填写表单,可以查看3 _ newpolicyoverrides步骤,该步骤包含一个虚假的保费计算实现。“应用程序表单”表单的定义是非常标准的。首先,定义一个表单对象,在预先生成的GlobalKey key键中处理它,然后定义元素,如4_newPolicyYou.dart文件和图14所示。

[图14] 4_newPolicyYou.dart是一个非常直观的表单定义。请注意,这里使用助手来减少代码。

表单可以以多种方式与数据交互,因此它们可以根据开发人员的偏好进行设计。如果需要伪双向绑定行为,onChange处理程序中的值可以保存到setState中。但是您也可以使用onSaved在表单完成后保存数据。我决定采用后一种方法。Step4Builder类(图15)包含向导序列。如果表单合法,请保存并继续。将数据注入表单的方法非常简单:因为我们将值从模型传递到表单中相应控件的初始值(processData),所以每次操作setState时,控件都会更新。

这就是为什么我们只需要填写模型的字段(过程数据。SetownerofromCount),然后使用这个。表单键(_ f).当前状态。重置以重置表单,这样我们可以重新计算字段的初始值,并直接从模型中获取该值。但是为什么要重置表单呢?因为这确保了只要我们不在表单中持久化这些值,我们就可以获得没有在setOwnerFromAccount中填充的字段的默认值(这些默认值也存在于模型中)。

这只是策略之一。我们可以在不同的情况下选择其他方法,但是应该注意的是,我们不一定需要采用某种方法。

[图15]步骤4生成器-如果表单是合法的,保存并移动到下一步。非常干净。

动态表单布局的实现与传统的js/html没有太大的不同。在向导的最后一步,5_newPolicySubject.dart中,我们应该创建保险单的保险对象的数据,因此我们需要根据数据类型(汽车、人或蜥蜴等)采用不同的形式。)。实现方法是在不同的小窗体中定义不同的字段集,然后根据上一步的选择显示相应的字段集。应用程序中只实现了一种类型(reptileObject.dart),但是只需签入构建方法就可以很容易地添加其他类型(图16)。

[图16] 5_newPolicySubject.dart:我只是想给我的宠物蜥蜴投保,所以唯一的表单定义是爬虫对象,但是当然我们可以通过在子属性中插入if语句来显示正确的表单。

现在,我们有一个文本框和一个下拉菜单。下一步是编写日期控件。事实上,控件并不存在。如果你开发了移动应用程序,这听起来可能很奇怪,但如果你仔细想想,这是完全合理的。最好的解决方案总是使用系统提供的输入(例如,我们不需要定义键盘控件,只需要使用系统提供的),而每个移动系统都提供自己的日期控件,通常是以日历的形式。因此,我们的“日期输入”只是一个只读的文本格式字段,当我们触摸控件时,它将要求系统提供一个值。前面提到的reptileObject.dart文件包含一个例子(图17-18)。

图17-18:reptileObject.dart - TextFormField的责任非常少,只需要告诉系统用户需要输入一个日期,然后显示该动作的结果即可。我们定义了一个onTap处理函数,来拦截针对控件的交互,然后显示系统的datepicker。由于这是一个异步的动作(用户可以花很长时间来选择日期),因此整个方法必须标记为异步。

验证使用errorColor

现在表单已经完成了,我们需要提供一些基本的数据验证。规则非常简单:每个表单控件有一个“validator”属性,它接受一个函数,函数的输入就是值,输出是一个字符串。如果输出非空,则输出的内容就表示验证错误消息,显示在适当的区域。图19演示了一个组合验证(两个条件、两条消息)的简单示例。

图19:简单的验证 - 如果Validations.required返回错误消息,则返回该消息。否则检查输入是否为有效的邮件地址。如果不是,则返回自定义的错误消息。

到这里一切都很顺利,但如果我们需要进行异步验证(比如检查用户名是否已存在)该怎么办?嗯……很难。Flutter不支持在验证中使用Future,而且应该永远不会支持,据说这样会破坏同步验证,而且由于这些原因(混合两种验证方式并不是很好的UI实践。

即使接受这个现实,我们也会遇到必须进行服务器端验证的情况,那么唯一的选择就是将海量的数据加载到设备上。不过幸运的是,有一个广为人知的非常简单的技巧。只需在验证器中执行调用然后切换一个局部标志。如果标志被设置,则不显示任何验证信息。当验证结束后将验证结果保存到某个局部变量中,然后切换该标志,然后手动触发表单的验证。这样,第一次验证触发时不会显示任何信息(或者可以显示“请稍候……”表示动作正在执行),第二次验证将验证信息改成动作的结果(需要覆盖“请稍候……”)。

因此,尽管我们可以这样进行异步验证,但还是希望SDK能提供支持。这样可行,但应该更干净一些。

不管如何,现在应用程序可以运行了,而且开发这个程序根本没有花太多时间。我们考虑了实现商业应用的绝大多数基本问题,而且并没有什么太难的地方。所以可以认为这个应用程序是成功的。我们现在可以去掉那个反面教材,清理下代码,与后台结合,然后在收到客户反馈后重新修改。

我们来看一看这个应用程序:

[图] 政策主题页面

最后的感想

那么,我们应该使用Flutter来开发移动应用吗?我认为需要考虑几个问题才能做出判断,不同的人可能会得出不同结果。

如果你是第一次开发此类移动应用,我会推荐你使用。Flutter的学习曲线非常平缓,也不需要任何前提知识。通过教程和各种文档可以很容易地判断哪些场景下应该使用什么,而采用的工具完全可以自行决定。在学习一个存在了许多年的框架时,一些太过明显的实践人们就不会再谈起,导致这些实践很难学到。由于Flutter相对比较新,因此没有什么显而易见的问题,因此也没有那些被埋在各种新功能下的人尽皆知的技巧。相反,对于经验丰富的移动开发者,对待Flutter的态度应该与其他新技术一样。在创建有很多功能的高级应用时,如果你对某个技术有经验,那么应用程序越大,该技术的优势就越大。但是,如果你要开发一个很小的应用,那么Flutter是快速开发中的无价之宝。

Flutter的社区依然在成长。社区还不是很大,但也不是太小。关于这一点大家的意见可能不一样,但我认为当前的社区大小已经足够支持小型到中型的开发。用户基础越大,边缘情况就被研究得越透彻,也就越容易找到帮助,所以只要社区依然在稳健成长,对大型项目的支持也会越来越完备,风险也会越来越小。

现在有许多Flutter开发的应用,因此已经不是小众框架了。从官方网站上可以看到,不仅Google在用,许多大牌公司也在用。这表明Flutter的技术支持计划在向好的方向发展,因此值得一试。考虑到该技术依然很新,因此这些公司很可能需要在推出应用程序之前进行一些研究,但研究之后依然选择了Flutter,所以证明Flutter可能已没有太大风险。只要有足够的时间,Flutter应该能够成为开发移动应用的首选。

众所周知,市场变化很快,但这并不能阻止我们探索新事物。而且毕竟看来Flutter值得我们去尝试。

原文链接:

本文为CSDN翻译文章,转载请注明出处。返回搜狐,查看更多

责任编辑:



黎平门户网 版权所有© www.burgers-online.com 技术支持:黎平门户网 | 网站地图