『CSDN』不用掉一根头发!用 Flutter + Dart 快速构建一款绝美移动 App( 五 )


[图10] AnimatedCrossFade 现在我们知道了怎样创建主页 , 并利用通用的列表项来显示用户的保单 。 接下来演示一下怎样给应用程序提供Mockoon API中的数据 。 我们打开DictionariesService(图11) 。
『CSDN』不用掉一根头发!用 Flutter + Dart 快速构建一款绝美移动 App
本文插图
[图11] DictionariesService 可以看到 , get函数标记为async , 意思是它的返回值会包裹在Future<>中 , 采用类似于promise的处理方式 。 http客户端会异步执行命令 , 然后提供响应结果、状态码等 。 紧接着我们将JSON(其类型默认为Map<String, dynamic>)映射为DTO对象 。 由于这些是字典 , 所以我为它们创建了map , 这样就不需要在显示某个代码对应的名称时遍历所有元素了(只需这样写即可:commonData.maps[DictCode.PRODUCT_TYPE][_policy.type]) 。接下来看看DTO 。 将json转成对象并没有公认的方法 , 但幸运的是我们可以利用很多插件 。 我这里使用了json_annotation(https://pub.dev/packages/json_annotation) , 用它来监视启动后(flutter packages pub run build_runner watch)就会寻找 @JsonSerializable标记并创建映射函数 , 如图12~13所示 。
『CSDN』不用掉一根头发!用 Flutter + Dart 快速构建一款绝美移动 App
本文插图
[图12] policy.dart - DTO类
『CSDN』不用掉一根头发!用 Flutter + Dart 快速构建一款绝美移动 App
本文插图
[图13] policy.g.dart - 由json_annotation生成 这可以大幅简化工作 , 并提供非常方便的方式将类映射到JSON 。
向导 每个成功的商业应用必不可少的两部分就是表单和验证 。 我们来看看我们要做的功能 , 以及保单向导的代码 。 前两步(1_newPolicyType , 2_newPolicyProduct)都是随处可见的、非常标准的东西 , 这里就不再赘述了 。 如果你想看看如何利用异步执行计算来填充表单 , 那么可以查看3_newPolicyCovers步骤 , 它包含了一个假的保费计算的实现 。
app表单 表单的定义非常标准——首先定义一个Form对象 , 在预先生成的GlobalKey<FormState>键中进行处理 , 然后定义元素 , 如4_newPolicyYou.dart文件和图14所示 。
『CSDN』不用掉一根头发!用 Flutter + Dart 快速构建一款绝美移动 App
本文插图
[图14] 4_newPolicyYou.dart——非常直观的表单定义 。 注意这里使用了Helper来减少代码 。表单可以通过多种方式与数据交互 , 所以可以按照开发者的喜好来设计 。 如果需要伪双向绑定行为 , 可以将onChange处理函数中的值持久化到setState中 。 但是也可以仅使用onSaved , 在表单完整之后再持久化数据 。 我决定采用后一种方法 。 Step4Builder类(图15)中包含了向导的序列——如果表单合法 , 则保存后继续 。 向表单中注入数据则采用了很简单的方法:由于我们从模型传递值给表单(processData)中相应控件的initialValue , 因此每次setState操作的时候控件都会被更新 。 这就是为何我们只需要填充模型的字段(processData.setOwnerFromAccount) , 然后使用this._formKey..currentState.reset重置表单即可 , 这样就可以重新计算字段的初始值——直接从模型中获取值 。 但是为什么要重置表单呢?因为这样可以保证 , 只要我们不持久化表单中的值 , 我们在setOwnerFromAccount中没有填充的字段就可以获得默认值(这些默认值也存在于模型中) 。这只是策略之一 。 在不同的情况下我们可能会选择其他方法 , 但要注意的是 , 我们并不需要一定采用某种方法 。
『CSDN』不用掉一根头发!用 Flutter + Dart 快速构建一款绝美移动 App
本文插图
[图15] Step4Builder - 如果表单合法 , 则保存并转向下一步 。 非常干净 。动态表单布局的实现跟传统的js/html没什么太大区别 。 在向导最后一步的5_newPolicySubject.dart中 , 我们应该创建保单投保对象的数据 , 因此需要根据数据类型(汽车、人或者蜥蜴等)来采用不同的表单 。 实现方法是在不同的小窗体中定义不同的字段集合 , 然后根据前一步的选择来显示合适的那个 。 应用程序中仅实现了一个类型(reptileObject.dart) , 但只需在build方法中检查一下就很容易实现添加其他的类型(图16) 。[图16] 5_newPolicySubject.dart:我只想为我的宠物蜥蜴投保 , 因此唯一的表单定义就是Reptile对象 , 但我们当然可以通过在子属性中插入if语句来显示正确的表单 。现在 , 我们有文本框和下拉菜单 , 下一步该编写日期控件了——其实控件并不存在 。 如果你开发过移动应用 , 也许这听上去有些奇怪 , 但是如果仔细考虑一下就会发现这完全合理 。 最好的方案永远是使用系统提供的input(例如 , 我们不需要定义键盘控件 , 只需要使用系统提供的即可) , 而每个移动系统都提供了自己的日期控件 , 一般表现为日历的形式 。 因此我们的“日期输入”仅仅是一个只读的TextFormField , 当我们触摸该控件时 , 它会要求系统提供值 。 前面提到的reptileObject.dart文件就包含了一个例子(图17-18) 。


推荐阅读