技术勇•无止尽
背景
项目本身就存在,只是之前是以PC端 + 微信小程序承载。对于客户、用户来说使用不友好,针对物流追踪、信息缓存、蓝牙打印等功能在小程序上实现效果并不好,APP的开发应用而生。
调研
其实调研因为结合自身开发团队情况,只调研了uni-app、flutter,所谓的跨平台解决方案。uni-app查看了安卓端的Demo就放弃了,切页面时有明显的链接跳转痕迹,像Html页面的切换。可能研究不深刻,初次印象比较差。Flutter的选择也是反复测试了下,并没有发现明显的交互问题。当然网络上对Flutter的风评也比较低,万物应皆原生的意味,最终都会回归原生。当然对于当下的我,Flutter在控本增效方面是优先选项。
环境搭建
因为我前端出身的缘故,采用了vscode + 夜神进行开发。首先执行flutter doctor -v详细诊断一下,主要错误是没装Visual Studio - develop for Windows,可能官方更推荐用Visual Studio工具进行开发。
Flutter 2.10.5 • channel stable
Tools • Dart 2.16.2
// 模拟设备
• Mate 20 Pro (mobile) • 127.0.0.1:62001 • android-x86 • Android 7.1.2 (API 25)
// 真机设备 - 数据线直接连接真机,手机打开开发者模式的USB调试,USB的连接方式改为‘文件传输’
// 真机调试主要是开发设备定位、蓝牙打印等针对手机原始功能基础上开发的功能
依赖库
都在站在前人肩上摸石头过河,Flutter的生态圈一直不温不火,网上资料相对比较少。当然少则少,日常开发基本满足。
environment:
sdk: '>=2.15.1 <3.0.0'
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
iconfont_dart: ^0.3.3
color_dart: ^0.2.1
flutter_swiper: ^1.1.6
provider: ^6.0.4
pull_to_refresh: ^2.0.0
dio: ^4.0.6
fluttertoast: ^7.1.6
shared_preferences: ^2.0.15
device_info_plus: ^2.2.0
fluro: ^2.0.3
oktoast: ^3.1.5
url_launcher: ^6.1.7
sp_util: ^1.0.2
keyboard_actions: ^3.3.1+1
qr_code_scanner: ^0.7.0
common_utils: ^2.1.0
rxdart: ^0.27.1
cached_network_image: ^3.2.0
bluetooth_print: ^3.0.1
json_annotation: ^4.6.0
flutter_easyrefresh: ^2.2.1
sticky_headers: ^0.2.0
city_pickers: ^1.1.0
flutter_my_picker: ^1.0.3
# 高德2D地图插件(支持Web) https://github.com/simplezhli/flutter_2d_amap
flutter_2d_amap:
git:
url: 'https://github.com/simplezhli/flutter_2d_amap.git'
encrypt: ^2.0.0
web_socket_channel: any
hprt_print: ^3.0.2
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^1.10.11
json_serializable: ^6.3.1
开发
瞎瞅了两天别人的项目源码,就直接开干了。
- 主要熟悉原生控件,
Scaffold、InkWell、Container、Column、Row、Expanded、Text等,类比理解 - 熟悉Flutter页面的生命周期
initState、build、dispose - 熟悉路由传参、页面之间通讯
- 封装顺自己意的自定义控件
- 重要的一点是构建自己的顺手样式类
备注:追求的是开发体验的快乐,顺手顺意。
列表页面
- 重写
build方法,返回一个控件Widget。 - 循环渲染每一个列表
item,构建列表主体,支持下拉刷新,上拉分页。 - 支持接口请求时列表
loading,无数据时主体填充。 - 布局上将界面分割成上下两部分,上面为列表主体部分,下面为操作按钮‘创建批次’。
- 使用封装的
NavigatorUtils.push(context, PortalRouter.batchFormPage)进行路由页面跳转。 - 使用封装的
PermissionUtil.hasPermission('cmpy_batch_add')进行按钮权限控制。 - 使用控件
CustomScrollView作为列表上下滚动容器。
@override
Widget build(BuildContext context) {
super.build(context);
final Widget bottomMenu = Container(
height: 60.0,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Theme(
data: Theme.of(context).copyWith(
buttonTheme: const ButtonThemeData(
height: 44.0,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Visibility(
visible: PermissionUtil.hasPermission('cmpy_batch_add'),
child: Expanded(
child: MyButton(
backgroundColor: Colours.app_main,
textColor: Colours.text_white,
text: '创建批次',
minHeight: 40,
minWidth: 160,
onPressed: () {
NavigatorUtils.push(context, PortalRouter.batchFormPage);
}))),
],
),
),
);
return Column(children: [
Expanded(
child: NotificationListener(
onNotification: (ScrollNotification note) {
if (note.metrics.pixels == note.metrics.maxScrollExtent) {
_loadMore();
}
return true;
},
child: RefreshIndicator(
onRefresh: _onRefresh,
displacement: 64.0, //40 + 24
/// 默认40, 多添加的80为Header高度
child: Consumer<BatchPageProvider>(
builder: (_, provider, child) {
return CustomScrollView(
/// 这里指定controller可以与外层NestedScrollView的滚动分离,避免一处滑动,5个Tab中的列表同步滑动。
/// 这种方法的缺点是会重新layout列表
controller: _tabIndex != provider.tabIndex ? _controller : null,
key: PageStorageKey<String>('$_tabIndex'),
slivers: <Widget>[
// SliverOverlapInjector(
// ///SliverAppBar的expandedHeight高度,避免重叠
// handle:
// NestedScrollView.sliverOverlapAbsorberHandleFor(context),
// ),
child!,
],
);
},
child: SliverPadding(padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), sliver: _listItems(context)),
),
),
)),
bottomMenu
]);
}
遇到的问题
- 空安全问题,对于常规的编码风格要求会更加严格。让你真正对每个变量、参数做出精准的判断处理。
- 布局控件搭配使用问题,会遇见各种奇奇怪怪的布局控件使用不兼容问题。仔细查看错误日志,认真分析,勇于思考,百度不出来。
- 关注各个手机屏幕下文本溢出、布局失效等问题。手动处理文本换行、布局修正。
- 对照接口文档手动编写
model类,比较费时间,时刻关注空安全。 - 依赖库中各个依赖包的兼容问题,慎重升级,否则可能搞一下午。
- 慎重升级开发工具,否则莫名报错,痛苦解决。
后记
开发过程经历过偶尔的痛苦阶段,还是很丝滑。Dart语法介于JavaScript和Java之间,页面生命周期类React(不过比React清晰很多)。APP性能方面并没有网传的交互卡顿,体验差等问题。