前言
Flutter 从发布之日起我就对其心心念念了好久。
奈何这段时间实在是太忙了,加之自己拖延症时不时发作下,一直都抽不出时间来学习这个跨平台框架。
一转眼 Flutter 1.2 都已经发布了,这下实在是坐不住了。特地花了一周的时间来做了 一文 这个 APP 。以此来简单了解下这款全新跨平台框架的魅力。
第一个 APP
回到标题,既然是编写第二个 Flutter APP,那就要求各位观众老爷自己对照着官方的 First Flutter APP 撸一遍。(中文链接:https://flutterchina.club/get-started/codelab/)
万事开头难,这部分包含了 dart 语言特性的学习,和 Flutter 框架一些特性的体验。
如果你也是像我一样只是花两个小时简单看了下 dart 语言的新特性就直接来撸第一个 APP。写的时候可能会感觉总是在云里雾里,很多地方都不明白。
别担心,这是正常现象,对我们这种只想初步体验的用户来说,没有系统的学习,这种情况才是正常现象。
保持开放的心态,多学多看。碰到不懂的,多查,碰到不知道怎么写的,多看官方的源码实现,等代码量上去了,自然就熟练了。
第二个 APP
照着官方示例完成了自己了的第一个 APP 编写,是不是很有成就感?激动之余,似乎感觉少了点什么。
没错,毕竟只是照着官方的示例敲了一遍,说是 APP 也略简陋了。是不是迫不及待的想做点什么来巩固下自己的学习呢。
这次就跟着我一起从项目的立项开始你的第二个 APP 吧。
一文
由于项目一周的时间限制,本次就要求项目尽可能的简单,页面尽可能的少。且,要尽可能的完成多的功能点,于是 一文 就诞生了。
一文 是基于每日一文 API 开发的一款全新的 Flutter APP。
下载
https://github.com/chengww5217/one_article/releases
截图
Highlights
- 这个项目足够简单
- 只有 splash、home、starred list 三个界面
- 这个项目功能点足够多
- splah 页面创建,去除启动白屏
- 联网、Json 解析、文章展示
- 数据库保存文章
- 主题切换,字体调整,配置本地保存(SP)
- 国际化
- ···
- 这个项目还是有用的
- 和一般纯练手 Demo 不同,每日一文是我每天都会看的
开始项目
注意:在源代码中,一个页面可能包含多个功能实现,在实际做的时候,请依据 APP 预览一项一项进行实现。
源代码并不是标准答案,有问题欢迎提交 PR 进行贡献。
API
API 来源:https://github.com/jokermonn/-Api/blob/master/OneArticle.md
分析 API 进行联网实现,主要要求实现联网获取文章,获取后进行 Json 解析到 bean,然后进行简单的错误 handle。
参考文章:
Splash Page
按照原生 APP 开发的套路,用于初始化以及展示广告的 Splash 是必不可少的。
第一个页面,主要要求掌握页面编写的常规套路以及 StatefulWidget 的生命周期等。
比如 class SplashPage
的写法:
class SplashPage extends StatefulWidget {
SplashPage({Key key, this.title}) : super(key: key);
final String title;
@override
State<StatefulWidget> createState() {
return _SplashPageState();
}
}
然后就是 class _SplashPageState
的编写。
布局就是一张图片:
import 'package:flutter/material.dart';
class SplashPage extends StatefulWidget {
SplashPage({Key key, this.title}) : super(key: key);
final String title;
@override
State<StatefulWidget> createState() {
return _SplashPageState();
}
}
class _SplashPageState extends State<SplashPage> {
@override
void initState() {
// TODO: do something to init
super.initState();
}
@override
Widget build(BuildContext context) {
return Builder(builder: (context) {
return Container(
child: Image(image: AssetImage('assets/images/splash.png'), fit: BoxFit.fill,),
);
});
}
}
生命周期如下:
图片转载自https://segmentfault.com/a/1190000015211309
具体 Splash 页面讲解参考我的博客:Flutter 开发 Android & IOS 启动页 splash page
Home Page
主页面主要是对文章进行展示以及相关设置项。
点击左上角可以弹出相关配置弹窗。
考虑到布局的复杂度,这里可以将底部弹窗抽离出单独写进一个 .dart
文件。
从这部分就涉及到各个控件的使用和状态设置,点击事件等内容。
这部分基本就是程序的核心内容了。
完成了该部分之后就是对程序进行优化,添加数据库来缓存数据,日期判断切换,文章收藏等。
这个部分是耗时最长的,也是从磕磕碰碰到逐渐熟练的过程。
杂项
最后就是国际化,添加资源和打包等一些杂项了,具体参见
https://flutter.dev/docs/development/accessibility-and-localization/internationalization
https://flutter.dev/docs/deployment/android
结语
从刚开始看 dart 语法,到这个项目开发完成。断断续续一共持续了三周的时间。每天抽出一到两个小时,合计一共是 56 小时左右。减去画 APP 图标,启动页面图片的两个小时,勉强算得上八小时工作制的一周。
这一周的使用过程中,Flutter 有些特性让人感觉相见恨晚:语法特性(类型动态检查,支持 .?
??
操作符)、简单方便完备的 UI 方案、Hot Reload等。但是诸如复杂冗长的 view tree、资源的硬编码、糟糕的 UI 控件 API 等又让人头痛不已。
在初步使用 Flutter 之后,我发觉似乎 Flutter 短时间内并不能让我不学习原生开发就直接使用 Flutter 解决移动客户端开发。
在不断的使(zhe)用(teng)过程中,发现碰到好多问题还是需要你必须用原生开发的知识去解决相应的问题。 比如项目里面获取已收藏文章,是这样从数据库里面获取文件的:
Future<List<ArticleBean>> getStarred() async {
List<ArticleBean> articles = List();
Database db = await getDB();
List<Map<String, dynamic>> maps =
await db.query(name, columns: [columnId, columnStarred, columnDate, columnData], where: "$columnStarred = ?", whereArgs: [true]);
if (maps.length > 0) {
for (Map<String, dynamic> map in maps) {
ArticleBean article = ArticleBean.fromJson(map);
articles.add(article);
}
}
return articles;
}
请看核心查询代码
await db.query(name, columns: [columnId, columnStarred, columnDate, columnData], where: "$columnStarred = ?", whereArgs: [true]);
这里就是获取所有 starred 为 true 的列。
但是实际运行的时候,发现在 Android 设备上面总是获取不到。
Android 数据库使用的是 Sqlite,不能存储 bool(boolean)。相反,布尔值被存储为整数 0(false)和 1(true)。
故上述代码要改成下面的代码才生效。
await db.query(name, columns: [columnId, columnStarred, columnDate, columnData], where: "$columnStarred > ?", whereArgs: [0]);
这只是一个很小的简单例子,但是也说明了在 Flutter 上面并不能总是帮你解决原生的一些坑(这其实取决于各个框架的开发者为你做了多少兼容处理)。
本文到这里就要结束了,不怎么涉及具体代码,只是一周时间的 Flutter 简单上手。如果大家对项目有兴趣,欢迎大家 star、fork 以及提交 PR,谢谢大家。