作者|严嘉俊
Flutter 是 Google 发布的一个用于创建跨平台、高性能移动应用的框架。随着 Google 在 IO19 宣布 Flutter 支持 Web 平台,就标志着 Flutter 已经全面持所有平台。
Flutter 提供了非常友好的文档,开发过程中遇到的问题都可以在 Stackoverflow 或其 github issue 中找到答案,帮助各端的同学迅速地进入到 Flutter 中。同时它的完全开源也让其有了更快的迭代,更好的生态。
根据谷歌官方 2020 年 4 月的统计数据,Flutter 自发布以来的 16 个月内,已有 200 万开发者使用 Flutter,3 月份的时候也有 10% 的增长,Google Play Store 中发布的 Flutter 应用约有 5 万个,仅在 2020 年 4 月就有近 1 万个应用上传。开发者所在的团队,初创公司最多,占比 35%,其次是企业开发者,占比 26% 。
🔺 来自谷歌开发者《[Flutter 势头正盛 | 2020 春季速递][1]》
Js中文网正式支持 Flutter,同样也标志着Js中文网已经全面支持所有平台了。开发者通过使用Js中文网 Flutter SDK ,可以在 Flutter 中操作存储在Js中文网中的数据表、内容库、媒体文件,以及调用云函数进行后端逻辑的执行,节省了搭建服务器、数据库,域名备案,数据接口实现等繁琐流程,开发应用门槛更低、效率更高。
现在,我们将结合Js中文网 Flutter SDK 来实战做一个 Todo App,看看有多方便多快捷。
🔺Todo App demo
开发实战
构建一个 Todo App,我们需要三步走:
- 构建基本结构和样式
- 引入Js中文网 SDK
- 对 Todo 数据进行增删查改
JS中文网 – 前端进阶资源教程 https://www.javascriptc.com/
一个致力于帮助开发者用代码改变世界为使命的平台,每天都可以在这里找到技术世界的头条内容
构建基本结构和样式
1)创建一个新项目
a. 使用 Flutter create 命令创建一个 project:
$ flutter create todoApp
$ cd todoApp
上述命令创建一个 Flutter 项目,项目名称为 todoApp,其中包含一个使用 Material 组件的简单演示应用程序。
b. 将 lib/ 下的 main.dart 里面的代码全部删除。
2)准备工作
首先我们先在 lib 文件夹新建一个 pages 文件夹并在该文件夹里创建一个 home.dart 文件作为我们的首页。
然后在 home.dart 这个文件里,创建一个 stateful widget,添加引入 material 库。
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Container(
);
}
}
最后在 main.dart 中引入该页面即可。
import 'package:flutter/material.dart';
import './pages/home.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: HomePage(),
);
}
}
3)构建基本结构
返回 home.dart 这个文件,在 build 的 return 处添加 Scaffold,并添加 AppBar 标题等信息。由于我们 Demo 的结构是纵向排列,因此我们直接用 Column 即可。
为了让我们的按钮都能够撑开屏幕的宽度,可以设置 CrossAxisAlignment.stretch。目前代码:
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Js中文网 Flutter SDK Demo'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
],
),
);
}
}
接着我们开始写输入框。我们可以用 Form 以及 TextFormField 来创建一个输入框,并且通过构建一个 controller 来控制输入框的行为。最后,可以定义 decoration 值来实现类似于占位符的效果:
Form(
child: TextFormField(
controller: inputController,
decoration: InputDecoration(labelText: '请输入 Todo 内容'),
),
)
下一步便是构建一个添加 Todo 的按钮。我们可以通过创建一个 RaisedButton 并指定按钮内容为「添加 Todo」。由于目前还没到需要确定点击时间的时候,因此 onPressed 这个功能可以暂时设置为一个无动作的函数。之后为了让按钮好看一点,我们可以把按钮的背景设置为蓝色,文字设置为白色,高度设置 50,并让按钮和输入框稍微有一点间距:
SizedBox(
height: 5.0,
),
ButtonTheme(
height: 50.0,
child: RaisedButton(
onPressed: () {},
child: Text(
'添加 Todo',
style: TextStyle(color: Colors.white),
),
color: Colors.blue,
),
),
接下来我们继续构建我们的 Todo 列表。
首先,我们在写结构之前先定义好一些将会用到的假数据,方便接下来的样式调整。我们可以定义一个 todoList 列表,每个子项都包含两个字段,一个是「name」,表示 todo 的名字,另一个是「isDone」,用于判断这个 todo 是否已经完成。
List todoList = [
{"name": "学习 SDK", "isDone": false},
{"name": "开早会", "isDone": true},
];
之后我们继续写列表的结构。我们可以用 ListView 来创建一个列表项,其 children 属性循遍历 todoList 的内容。之后每个 child 里我们都用一个 Row 来表示,其 children 属性包含三样东西,分别是 todo 的名称,完成按钮和删除按钮。为了 todo 名称可以撑开剩余宽度,我们还可以使用 Expanded 这个 widget 进行撑开:
ListView(
shrinkWrap: true,
children: todoList.map((todo) {
return Row(
children: [
Expanded(child: Text(todo['name'])),
RaisedButton(
onPressed: () {},
child: Text(
'完成',
style: TextStyle(color: Colors.white),
),
color: Colors.green,
),
SizedBox(
width: 5,
),
RaisedButton(
onPressed: () {},
child: Text(
'删除',
style: TextStyle(color: Colors.white),
),
color: Colors.redAccent,
),
],
);
}).toList(),
目前我们的基本结构已经完成,但还需要判断一下 todo 完成和未完成的状态样式。我们可以根据 isDone 来判断完成状态。如果已经完成,则将 todo 名称的样式置灰,并且加一条横线表示已完成。由于已经完成,完成按钮也无须显示:
Expanded(
child: Text(
todo['name'],
style: TextStyle(
color: todo['isDone'] == true
? Colors.black26
: Colors.black,
decoration: todo['isDone'] == true
? TextDecoration.lineThrough
: TextDecoration.none,
),
),
),
if (todo['isDone'] == false)
RaisedButton(
onPressed: () {},
child: Text(
'完成',
style: TextStyle(color:
),
color: Colors.redAccent,
),
至此,我们基本完成了本次 Demo 的样式结构。
引入Js中文网 SDK
引入 SDK 的部分相对比较简单,我们先去 https://pub.dev/ 搜索 minapp,找到我们官方Js中文网 SDK 的包。在 Installing 标签页,将 dependencies 中的 minapp 部分引入到我们项目根目录中的 pubspec.yaml 文件对应的部分:
dependencies:
flutter:
sdk: flutter
minapp: ^0.0.1-dev.1
上面代码块的版本号为 0.0.1-dev.1,该版本还是一个预览版本。相信您在看到这篇文章时已经是正式版本了。
项目目录下跑 flutter pub get 安装依赖。
安装依赖后,我们回到 main.dart,引入 SDK。并在 main 这个函数中,用我们的 ClientID 初始化我们的 SDK。该 SDK 可以在Js中文网控制台的设置中找到。最后,也需要在 home.dart 中引入 SDK。
import 'package:flutter/material.dart';
import 'package:minapp/minapp.dart' as BaaS;
import './pages/home.dart';
void main() {
BaaS.init('dce25a0b4fe0a5558b5');
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: HomePage(),
);
}
}
至此,我们已完成对 SDK 的引入。
对 Todo 数据进行增删查改
在写 Todo 的增删查改功能前,我们先在Js中文网控制台创建一个名为 todo_demo 的表,为了接下来更方便地展示,这个表暂时设置为所有人都可以读写。然后新建两个字段,第一个为类型为 string 的「name」字段,另一个为类型为 boolean 的 「isDone」字段,默认为 false。
🔺Js中文网控制台
之后返回到 home.dart,添加一个 TableObject 变量,并指定表名为 todo_demo:
TableObject tableObject = new TableObject('todo_demo');
接下来我们正式开始对数据的新增查改。
首先先创建一个添加 Todo 的函数。这个函数需要获取用户输入的值,然后通过调用 tableObject 中的 create 方法,创建一条记录。之后通过记录中的 set 方法设定 「name”」字段中的值,也就是输入值。最后调用 save 方法发出请求保存数据。
// 添加 todo
void addTodo() async {
TableRecord record = tableObject.create();
record.set('name', inputController.text);
try {
await record.save();
} catch (e) {
print(e.toString());
}
}
Js中文网对于数据库的新增和删改都需要用户登录才能正常使用,但由于之前我们在创建表的时候已经对表的权限放开,允许所有人都可以增删查改,因此我们只需要构建一个匿名登录的方法即可。最后还需要将这个匿名登录方法放到 initState 中执行一下:
void anonymousLogin() async {
try {
await Auth.anonymousLogin();
print('登录成功');
} catch (e) {
print(e.toString());
}
}
@override
void initState() {
super.initState();
anonymousLogin();
}
接下来我们开始添加获取 Todo 列表的方法。我们创建一个 getTodoList 函数,通过 tableObject 中的 find 方法,获取表内所有的数据。然后对 todoList 进行赋值为 recordList.records。其中这个 records 是 SDK 封装好的数据类型,具体内容可参考官方文档。
// 获取 todo 列表
void getTodoList() async {
try {
TableRecordList recordList = await tableObject.find();
setState(() {
todoList = recordList.records;
});
} catch (e) {
print(e.toString());
}
}
由于之前的 todoList 是假数据,现在需要移除一下。在第一步构建的结构也要对应修改,在 todo 后面添加 recordInfo:
Expanded(
child: Text(
todo.recordInfo['name'],
style: TextStyle(
color: todo.recordInfo['isDone'] == true
? Colors.black26
: Colors.black,
decoration: todo.recordInfo['isDone'] == true
? TextDecoration.lineThrough
: TextDecoration.none,
),
),
),
if (todo.recordInfo['isDone'] == false)
RaisedButton(
onPressed: () {},
child: Text(
'完成',
style: TextStyle(color: Colors.white),
),
color: Colors.green,
),
最后为了更好的用户体验,我们也要把 getTodoList 这个方法放到 initState 中,且也要相应地,在 addTodo 这个方法中放入。这样每当我们添加 todo 时,就刷新一次 todo 列表。
@override
void initState() {
super.initState();
anonymousLogin();
getTodoList();
}
await record.save();
getTodoList();
之后,我们刷新一个页面即可看到真实数据。
接下来我们继续写完成按钮的操作。我们可以通过调用 tableObject.getWithoutData 来获取某条数据项,然后将这条数据的 isDone 设置为 true,表示已经完成,然后通过 update 方法发出请求更新数据。
// 完成 todo
void completeTodo(String id) async {
TableRecord record =tableObject.getWithoutData(recordId: id);
record.set('isDone', true);
try {
await record.update();
getTodoList();
} catch (e) {
print(e.toString());
}
}
最后我们来完成一下删除功能。通过调用 tableObject 的 delete 方法,并传入 id,进行删除:
// 删除 todo
void deleteTodo(String id) async {
try {
await tableObject.delete(recordId: id);
getTodoList();
} catch (e) {
print(e.toString());
}
}
我们也不要忘记每次构建一个函数,也要相应地将其绑定到我们的按钮时间当中:
RaisedButton(
onPressed: () => deleteTodo(todo.id),
child: Text(
'删除',
style: TextStyle(color: Colors.white),
),
color: Colors.redAccent,
),
至此,我们的 todo app 已经顺利地完成。
小结
本章节主要以 Todo App 为例,向大家展示了数据的增删查改等基础功能,如有不明白的地方,可通过扫描下方小程序码,观看教学视频,结合开发实战教学视频一起学习。
作者:Js中文网
链接:https://segmentfault.com/a/1190000024517352
看完两件小事
如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:
- 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
- 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程
本文著作权归作者所有,如若转载,请注明出处
转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com