一,概述
表單時一個包含表單元素的區域。 表單元素允許用戶輸入內容,比如文本域,下拉列表,單選框,復選框等。常見的應用場景有:登錄,注冊,輸入信息等。
表單里有兩個重要的組件:
- Form:用來做整個表單提交使用
- TextFormField:用來做用戶輸入。
正式向服務器提交數據前,都會對各個輸入框數據進行合法性校驗。但對每個TextField都分別校驗很麻煩。
如果想清除一組TextfFiled的內容,一個個清除也很麻煩。所以,Flutter提供了一個Form widget,可以對輸入框進行分組,然后進行一些統一的操作。
二,構造函數
- Form:
- 介紹:Form繼承自StatefulWidget對象,它對應的狀態類為FormState
- 構造函數:
const Form({ Key key, @required this.child, this.autovalidate = false, this.onWillPop, this.onChanged, }) : assert(child != null), super(key: key);
-
參數含義
autovalidate:是否自動校驗輸入內容;當為 true 時,每一個子FormField內容發生變化時都會自動校驗合法性,並直接顯示錯誤信息。否則,需要通過調用 FormState.validate() 來手動校驗. onWillPop:決定Form所在的路由是否可以直接返回(如點擊返回按鈕),該回調返回一個 Future 對象,如果Future的最終結果是false,則當前路由不會返回;如果為 true ,則會返回到上一個路由。此屬性通常用於攔截返回按鈕。 onChanged:Form的任意一個子FormField內容發生變化時會觸發此回調。
- FormField:
- 介紹:Form的子孫元素必須是FormField類型,FormField是一個抽象類,定義幾個屬性,FormState內 部通過它們來完成操作
- 構造函數:
const FormField({ Key key, @required this.builder, this.onSaved, this.validator, this.initialValue, this.autovalidate = false, this.enabled = true, }) : assert(builder != null), super(key: key);
- 參數含義:
FormFieldSetter<T> onSaved, //保存回調 FormFieldValidator<T> validator, //驗證回調 T initialValue, //初始值 bool autovalidate = false, //是否自動校驗。
- 補充:Flutter提供了一個TextFormField widget,它繼承自FormField類,也是 TextField的一個包裝類,所以除了FormField定義的屬性之外,它還包括TextField的屬性。
- FormState:
- 介紹:FormState為Form的State類,可以通過 Form.of() 或GlobalKey獲得。可以通過它來對 Form的子孫FormField進行統一操作。
- 構造函數:無自定義構造函數
- 常用的三個方法:
FormState.validate() :調用此方法后,會調用Form子孫FormField的validate回調,如 果有一個校驗失敗,則返回false,所有校驗失敗項都會返回用戶返回的錯誤提示。 FormState.save() :調用此方法后,會調用Form子孫FormField的save回調,用於保存表單 內容. FormState.reset() :調用此方法后,會將子孫FormField的內容清空。
三,TextField, FormField
- 從最基礎的講起,對於TextField就是android中的edittext,就是一個輸入框( TextField class),這個輸入框常用的屬性如下:
child: new TextField( autocorrect: false, // 是否自動校正 autofocus: false, //自動獲取焦點 enabled: true, // 是否啟用 inputFormatters: [], //對輸入的文字進行限制和校驗 keyboardType: TextInputType.text, //獲取焦點時,啟用的鍵盤類型 maxLines: 2, // 輸入框最大的顯示行數 maxLength: 3, //允許輸入的字符長度/ maxLengthEnforced: false, //是否允許輸入的字符長度超過限定的字符長度 obscureText: true, // 是否隱藏輸入的內容 onChanged: (newValue) { // print(newValue); // 當輸入內容變更時,如何處理 }, onSubmitted: (value) { // print("whar"); // 當用戶確定已經完成編輯時觸發 }, style: new TextStyle( color: new Color(Colors.amberAccent.green)), // 設置字體樣式 textAlign: TextAlign.center, //輸入的內容在水平方向如何顯示 decoration: new InputDecoration( labelText: "城市", icon: new Icon(Icons.location_city), border: new OutlineInputBorder(), // 邊框樣式 helperText: 'required', hintText: '請選擇你要投保的城市', prefixIcon: new Icon(Icons.android), prefixText: 'Hello'), ),
- 輸入處理
其實對於一個輸入框,我們最關心的無非就是監聽輸入的內容,然后輸入完成后,輸入框中的內容是什么,文檔中寫的很清楚,textfiled控件有三個回調函數
在這里我們只需要關注onChanged和onSubmitted即可。
child: new TextField( controller: _controller, decoration: new InputDecoration(labelText: 'Your Name'),
onChanged: (val) { print(val); },
onSubmitted: (String v) { print(v); }, ),
- 顧名思義:
onChanged事件,在輸入內容發生變化的時候觸發,onSubmitted事件,則是在輸入結束,點擊完成的時候觸發。 然而在TextFormField中沒有這兩個事件,取而代之的是validator,onSaved,onFieldSubmitted 他們都接受三個函數,並且將其值作為參數傳遞到函數里面validator,如果開啟autovalidate: true,那么將會自動檢驗輸入的值,如果沒有則會在表單提交的時候檢驗 該函數只允許返回驗證失敗的錯誤信息以及驗證通過時返回null。onSaved, 當調用FormState.save方法的時候調用。onFieldSubmitted, 與onSubmitted一樣,則是在輸入結束,點擊完成的時候觸發。
- 編輯控制
無論是在TextField還是TextFormField中,都有一個重要的屬性controller,該屬性可用來對輸入框內容進行控制。 先創建一個控制對象:
TextEditingController _controller = new TextEditingController(); TextEditingController _formFieldController = new TextEditingController();
為輸入框初始化值以及注冊一個監聽事件:
@override void initState() { // TODO: implement initState super.initState(); _controller.value = new TextEditingValue(text: 'Hello'); _formFieldController.addListener(() { print('listener'); }); }
觸發一個監聽事件:
void _textFieldAction() { // print(_formFieldController.selection); // print(_formFieldController.text); //獲取輸入內容 print(_formFieldController.hasListeners); //判斷是否注冊監聽事件 _formFieldController.notifyListeners(); //觸發監聽事件 }
四,示例代碼
import 'package:flutter/material.dart'; void main() => runApp(new HomePage()); class HomePage extends StatefulWidget { @override _HomePageState createState() => new _HomePageState(); } class _HomePageState extends State<HomePage> { GlobalKey<FormState> _formKey = new GlobalKey<FormState>(); String _name; String _password; void _forSubmitted() { var _form = _formKey.currentState; if (_form.validate()) { _form.save(); print(_name); print(_password); } } @override Widget build(BuildContext context) { // TODO: implement build return new MaterialApp( title: 'Flutter data', home: new Scaffold( appBar: new AppBar( title: new Text('Flutter Form'), ), floatingActionButton: new FloatingActionButton( onPressed: _forSubmitted, child: new Text('提交'), ), body: new Container( padding: const EdgeInsets.all(16.0), child: new Form( key: _formKey, child: new Column( children: <Widget>[ new TextFormField( decoration: new InputDecoration( labelText: 'Your Name', ), onSaved: (val) { _name = val; }, ), new TextFormField( decoration: new InputDecoration( labelText: 'Password', ), obscureText: true, validator: (val) { return val.length < 4 ? "密碼長度錯誤" : null; }, onSaved: (val) { _password = val; }, ), ], ), ), ), ), ); } }
五,官方文檔
表單 Widgets