在一個正常的應用程序中, 表單是用戶交互的很重要的一部分
flutter 中你可以自己"綁定"用戶的輸入數據和 state 中的字段
當然, 還有另一個選擇, Flutter 內置了 Form
組件給我們使用, 這個組件是 flutter 框架提供出來幫助我們操作表單的一個組件, 應該是官方較爲推薦的方案
不過 Form
的相關中文文章不太多, 基本都是介紹一下 TextFormField
的使用, 更多的 api 雲裏霧裏的, 可能有些朋友不太好理解
我粗略的解析下源碼和自定義, 幫助看過的朋友理解下 Form
體系
文章目錄
Form 體系的簡單使用
自動校驗
官方提供給了我們一些組件來結合 Form
使用, 最常見的就是 TextFormField
import 'package:flutter/material.dart';
class SimpleUseComponent extends StatefulWidget {
@override
_SimpleUseComponentState createState() => _SimpleUseComponentState();
}
class _SimpleUseComponentState extends State<SimpleUseComponent> {
@override
Widget build(BuildContext context) {
return Form(
onChanged: () {
print("form change");
},
child: Column(
children: <Widget>[
TextFormField(
initialValue: "你好",
validator: (value) {
if (value.isEmpty) return "不能爲空";
return null;
},
autovalidate: true,
),
],
),
);
}
}
當我輸入/刪除時, 會出現日誌: ‘form change’
有一個autovalidate
的屬性, 這個屬性可以在TextFormField
設置,也可以在Form
設置, 自動提交驗證的意思, 默認是 false
.
當我將所有字符都刪除時, 會出現’不能爲空’的提示. 這個是由 validator
實現的, 因爲我設置了autovalidate
爲 true
, 然後這個返回值如果是 null
, 則說明驗證通過, 不通過則返回不通過的字符串.
點擊後校驗
當然,有些表單不要求自動校驗, 可能是點擊某個按鈕後來校驗, 這種情況下, 就需要使用 Form.of
來獲取到表單狀態
話不多說, 代碼在下面:
class SimpleUseClickComponent extends StatefulWidget {
@override
_SimpleUseClickComponentState createState() =>
_SimpleUseClickComponentState();
}
class _SimpleUseClickComponentState extends State<SimpleUseClickComponent> {
@override
Widget build(BuildContext context) {
return Form(
onChanged: () {
print("form change");
},
child: Column(
children: <Widget>[
TextFormField(
validator: (value) {
if (value.isEmpty) return "不能爲空";
return null;
},
),
Builder( // 這個 Builder 是
builder: (ctx) => RaisedButton(
child: Text('check'),
onPressed: () {
final formState = Form.of(ctx);
formState.validate(); // 驗證
// formState.reset(); // 重置
// formState.save(); // 保存
},
),
),
],
),
);
}
}
validate
會觸發 FormState
的 validation
回調
reset
會觸發 FormFieldState
的 reset
回調, 默認實現是將輸入框設置爲初始值
save
會觸發 FormFieldState
的 save
回調, 可以在裏面寫一些邏輯(比如保存信息到數據庫等等)
Form 體系源碼
架構查看
Form
組件是 widgets 包內的的一個 Widget
, 不是 Material
和 Cupertino
包內的, 它沒有用戶界面, 更多的是邏輯層面的一個組件
Form
體系中有 5 個類, 3 個 typedef
組成
FormScope
是一個InheritedWidget
, 一般帶of
方法的組件都會對應一個這個東西, 是獲取 Form
中 FormState
的容器類
FormState
就是 Form
對應的 state
FormField
是Form
下的子組件的通用類, 每個實現/繼承了這個類的子類就可以被Form
管理, 比如 TextFieldForm
就是這麼一個組件
FormFieldState
是 FormField
對應的狀態, 其中包含了一些狀態信息
源碼解析
通過回調等手段實現了內部的交互, 詳細看截圖
Form 解析
FormState 解析
FormField 解析
FormFieldState 解析
自定義 Form 子組件
有的時候表單中並不只有文本輸入, 還會有 Checkbox
等組件, 我這裏舉兩個例子來自定義一個 Form
子組件
自定義 CheckboxFormField
import 'package:flutter/material.dart';
class CheckboxFormField extends FormField<bool> {
CheckboxFormField({
bool initValue,
}) : super(
builder: CheckboxFormField.buildWidget,
initialValue: initValue,
);
static Widget buildWidget(FormFieldState<bool> field) {
return Checkbox(
onChanged: (bool value) {
field.didChange(value);
},
value: field.value,
);
}
}
一個簡單的自定義 CheckboxFormField
就完成了
置入 Form
中
import 'package:flutter/material.dart';
import 'custom_field.dart';
class FormComponent extends StatefulWidget {
@override
_FormComponentState createState() => _FormComponentState();
}
class _FormComponentState extends State<FormComponent> {
@override
Widget build(BuildContext context) {
return Form(
onChanged: () {
print("on change");
},
child: ListView(
children: <Widget>[
CheckboxFormField(),
],
),
);
}
}
當我點擊時, 就會回調 on change
自定義 SliderFormField
class SliderFormField extends FormField<double> {
SliderFormField()
: super(
builder: SliderFormField.buildWidget,
initialValue: 50,
);
static Widget buildWidget(FormFieldState<double> field) {
return Slider(
onChanged: (double value) {
field.didChange(value);
},
value: field.value,
min: 0,
max: 100,
divisions: 100,
);
}
}
置入 Form 中
import 'package:flutter/material.dart';
import 'custom_field.dart';
class FormComponent extends StatefulWidget {
@override
_FormComponentState createState() => _FormComponentState();
}
class _FormComponentState extends State<FormComponent> {
GlobalKey<FormState> formKey = GlobalKey();
@override
Widget build(BuildContext context) {
return Form(
key: formKey,
onChanged: () {
print("on change");
},
child: ListView(
children: <Widget>[
CheckboxFormField(),
SliderFormField(),
RaisedButton(
onPressed: () {
formKey.currentState.reset();
},
child: Text("reset"),
),
],
),
);
}
}
加入了一個Key
用於獲取FormState
, 觸發reset
方法
截圖:
後記
本篇解析了一下 Form 的使用和源碼, 幫助朋友們更好的理解使用
以上