「本文已參與好文召集令活動,點擊查看:後端、大前端雙賽道投稿,2萬元獎池等你挑戰!」前端
以前幾篇分別介紹了利用 Dio 完成後臺數據的獲取、刪除和編輯,相關文章以下:git
本篇介紹如何使用 Post 請求建立動態數據,本篇相關知識點以下:後端
在導航欄右上角增長操做按鈕是十分常見的狀況,Flutter 的 AppBar
組件提供了actions
參數,用於設置右上角的操做按鈕,actions
是一個 List<Widget>
,意味着能夠添加多個組件。本例增長了一個圖標按鈕,用於進入添加動態頁面:markdown
appBar: AppBar(
title: Text('動態', style: Theme.of(context).textTheme.headline4),
actions: [
IconButton(
icon: Icon(Icons.add),
onPressed: () {
RouterManager.router
.navigateTo(context, RouterManager.dynamicAddPath);
})
],
brightness: Brightness.dark,
),
//...
複製代碼
RouterManager.dynamicAddPath
是添加頁面的路由路徑常量,爲 /dynamics/add
。可是,咱們會發現這個路由規則和/dynamics/:id
,即動態詳情的實際是能夠匹配的,一不當心就跳到了詳情頁而不是添加頁面,這個時候該怎麼處理呢?網絡
Fluro 的路由匹配次序是按照定義路由的前後次序進行匹配的,所以須要把更具體的路由放置在範圍匹配的前面,即定義添加頁面路由時要放置在詳情路由的前面。這點實際上和 React Router相似,匹配到了就跳出規則,再也不往下匹配。所以,在使用 Fluro 的時候須要注意定義路由的次序,不然可能會致使路由跳轉不正確。app
添加頁面的表單和編輯頁面同樣,只是沒有從後臺讀取數據填充表單內容。咱們先直接複製以前的 dynamic_edit.dart 文件,並重命名爲 dynamic_add.dart,同時將DynamicEdit
替換爲 DynamicAdd
。與編輯頁面的不一樣之處在於:less
Map<String, Map<String, Object>> _formData = {
'title': {
'value': '',
'controller': TextEditingController(),
'obsecure': false,
},
'content': {
'value': '',
'controller': TextEditingController(),
'obsecure': false,
},
'imageUrl': {
'value': '',
'controller': TextEditingController(),
'obsecure': false,
},
};
複製代碼
_handleSubmit() async {
if ((_formData['title']['value'] as String).trim() == '') {
Dialogs.showInfo(this.context, '標題不能爲空');
return;
}
if ((_formData['content']['value'] as String).trim() == '') {
Dialogs.showInfo(this.context, '內容不能爲空');
return;
}
if ((_formData['imageUrl']['value'] as String).trim() == '') {
Dialogs.showInfo(this.context, '圖片連接不能爲空');
return;
}
try {
Map<String, String> newFormData = {};
_formData.forEach((key, value) {
newFormData[key] = value['value'];
});
var response = await DynamicService.post(newFormData);
if (response.statusCode == 200) {
Dialogs.showInfo(context, '添加成功');
} else {
Dialogs.showInfo(this.context, response.statusMessage);
}
} on DioError catch (e) {
Dialogs.showInfo(this.context, e.message);
} catch (e) {
Dialogs.showInfo(this.context, e.toString());
}
}
複製代碼
咱們會發現有不少方法是相似的,好比表單、表單校驗以及編輯時表單數據處理。所以這些共同的地方能夠進行封裝,可是須要考慮實際業務添加和編輯的表單內容可能不一樣,好比某些字段不容許編輯等,所以考慮共通性,咱們作更通用的處理,提取一個 dynamic_form.dart 類,將通用的部分統一封裝進去,提升複用性。async
class DynamicForm extends StatelessWidget {
final Map<String, Map<String, Object>> formData;
final Function handleTextFieldChanged;
final ValueChanged<String> handleClear;
final String buttonName;
final Function handleSubmit;
const DynamicForm(this.formData, this.handleTextFieldChanged,
this.handleClear, this.buttonName, this.handleSubmit,
{Key key})
: super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: Column(children: _getForm(context)),
);
}
List<Widget> _getForm(BuildContext context) {
List<Widget> widgets = [];
formData.forEach((key, formParams) {
widgets.add(FormUtil.textField(key, formParams['value'],
controller: formParams['controller'] ?? null,
hintText: formParams['hintText'] ?? '',
prefixIcon: formParams['icon'],
onChanged: handleTextFieldChanged,
onClear: handleClear));
});
widgets
.add(ButtonUtil.primaryTextButton(buttonName, handleSubmit, context));
return widgets;
}
}
複製代碼
封裝完以後,編輯和添加頁面的_formData須要增長將構建 TextField 的字段補齊,而不是以前那樣寫死,這樣更靈活。而且,代碼將更爲簡潔,以添加頁面爲例。ide
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('添加動態'),
brightness: Brightness.dark,
),
body: DynamicForm(
_formData,
_handleTextFieldChanged,
_handleClear,
'提交',
_handleSubmit,
),
);
}
複製代碼
調試過程當中發現,點擊提交按鈕時保存的數據會有多條。Flutter 如何防重提交? oop
通常防重提交的處理方法一種是點擊後禁用,等待網絡請求結果返回後再啓用按鈕。另一種方式就是增長Loading蒙層,在網絡請求沒結束前使用蒙層將頁面遮擋,從而避免操做表單及按鈕。這裏咱們採用第二種方式,經過蒙層的方式指示能夠避免操做表單,也可以給出加載指示。
在 pub 上提供了一個 flutter_easyloading
的插件,能夠知足這要求。具體使用是在main.dart
的 MatertialApp 的 builder
參數傳遞EasyLoading.init()
方法,初始化一個全局的EasyLoading
對象,以後就能夠在頁面中隨時調用了。顯示的時候調用 showXXX
方法,消失的時候調用 dismiss
方法,能夠設置多種 loading
樣式,也支持自定義 loading
組件以及自定義參數,具體能夠參考:flutter_easyloading。咱們在提交前顯示EasyLoading
,接收到數據後移除EasyLoading
便可。
_handleSubmit() async {
//...校驗代碼
EasyLoading.showInfo('請稍候...', maskType: EasyLoadingMaskType.black);
//...網絡請求代碼
EasyLoading.dismiss();
}
複製代碼
本篇介紹了新增數據頁面的示例,同時對於編輯和添加的頁面重複部分經過封裝共用的表單組件簡化了頁面結構和提升複用性。考慮實際操做的重複點擊,還引入了 flutter_easyloading 來實現加載蒙層的效果。源碼已提交至:網絡章節源碼。注意運行時拉取最新的後臺代碼運行,以避免找不到後臺服務加載不了數據。