作者|嚴嘉俊
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 春季速遞》
知曉雲正式支持 Flutter,同樣也標誌着知曉雲已經全面支持所有平臺了。開發者通過使用知曉雲 Flutter SDK ,可以在 Flutter 中操作存儲在知曉雲中的數據表、內容庫、媒體文件,以及調用雲函數進行後端邏輯的執行,節省了搭建服務器、數據庫,域名備案,數據接口實現等繁瑣流程,開發應用門檻更低、效率更高。
現在,我們將結合知曉雲 Flutter SDK 來實戰做一個 Todo App,看看有多方便多快捷。
🔺Todo App demo
開發實戰
構建一個 Todo App,我們需要三步走:
- 構建基本結構和樣式
- 引入知曉雲 SDK
- 對 Todo 數據進行增刪查改
可下拉至文末,直接觀看教學視頻。
構建基本結構和樣式
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('知曉雲 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 的樣式結構。
引入知曉雲 SDK
引入 SDK 的部分相對比較簡單,我們先去 https://pub.dev/ 搜索 minapp,找到我們官方知曉雲 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 可以在知曉雲控制檯的設置中找到。最後,也需要在 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 的增刪查改功能前,我們先在知曉雲控制檯創建一個名爲 todo_demo 的表,爲了接下來更方便地展示,這個表暫時設置爲所有人都可以讀寫。然後新建兩個字段,第一個爲類型爲 string 的「name」字段,另一個爲類型爲 boolean 的 「isDone」字段,默認爲 false。
🔺知曉雲控制檯
之後返回到 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());
}
}
知曉雲對於數據庫的新增和刪改都需要用戶登錄才能正常使用,但由於之前我們在創建表的時候已經對錶的權限放開,允許所有人都可以增刪查改,因此我們只需要構建一個匿名登錄的方法即可。最後還需要將這個匿名登錄方法放到 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 爲例,向大家展示了數據的增刪查改等基礎功能,如有不明白的地方,可通過掃描下方小程序碼,觀看教學視頻,結合開發實戰教學視頻一起學習。
👉 掃描下方小程序碼,觀看教學視頻
👉 PC 端可點這裏觀看教學視頻
另外,提到 Flutter,大家可能會聯想起 SwiftUI。關於 SwiftUI 開發實戰,我們也以新聞資訊 App 爲例,提供了開發實戰教程。有興趣的小夥伴可點擊下方標題鏈接進行學習。
如果有其它學習需求,可通過文末評論或小曉雲微信留言(微信號:minsupport4),我們將根據實際反饋情況安排下期實戰教學,敬請期待。
💡教程預告:App Clips 蘋果牌小程序完整版 demo 教程。