表單組件是個包含表單元素的區域,表單元素容許用戶輸入內容,好比:文本區域,下拉表單,單選框、複選框等,常見的應用場景有:登錄、註冊、輸入信息等。表單裏有兩個重要的組件,一個是Form組件用來作整個表單提交使用的,另外一個是TextFormField組件用來作用戶輸入的。html
屬性 | 類型 | 說明 |
Key | Key | 組件在整個Widget樹中的key值 |
autovalidate | bool | 是否自動提交表單 |
child | Widget | 組件child只能有一個組件 |
onChange | VoidCallback | 當FormField值改變時的回調函數 |
屬性名 | 類型 | 說明 |
autovalidate | bool | 自動驗證值 |
initalValue | T | 表單字段初始值,好比:輸入收穫地址時,默認回填本的地址信息 |
onSaved | FormFieldSetter<T> | 當Form表單調用保存方法Save時回調的函數 |
validator | FormFieldValidator<T> | Form表單驗證器 |
對於輸入框咱們最關心的時輸入內容是否合法,好比郵箱地址是否正確,電話號碼是不是數字等等,等用戶輸入完成後,咱們須要知道輸入框輸入的內容。那麼咱們要如何才能獲取到表單對象呢?爲了獲取表單的實例,咱們須要設置一個全局類型的key,經過這個key的屬性,來獲取表單對象:app
GlobalKey<FormState> globalKey = new GlobalKey<FormState>();
咱們來簡單的寫一個登錄頁面,校驗輸入框內的內容,當內容不合法時,並給出相應的提示:ide
import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; void main() => runApp(DemoApp()); class DemoApp extends StatefulWidget{ @override _DemoAppState createState() => new _DemoAppState(); } class _DemoAppState extends State<DemoApp> { String userName; String userPwd; GlobalKey<FormState> globalKey = new GlobalKey<FormState>(); void check(){ var loginForm = globalKey.currentState; //驗證表單 if(loginForm.validate()){ loginForm.save(); Fluttertoast.showToast(msg: '信息提交成功',toastLength: Toast.LENGTH_LONG,gravity: ToastGravity.BOTTOM,textColor: Colors.white); } } @override Widget build(BuildContext context) { return new MaterialApp( debugShowCheckedModeBanner: false, title: 'From表單Demo', home: new Scaffold( appBar: new AppBar( title: new Text('Form表單Demo'), leading: Icon(Icons.menu,size: 30,), actions: <Widget>[ IconButton(icon: Icon(Icons.search),iconSize: 30, onPressed: null) ], ), body: new Column( children: <Widget>[ new Form( key: globalKey, child: new Column( children: <Widget>[ new TextFormField( decoration: new InputDecoration( labelText: '請輸入用戶名', ), onSaved: (value){ userName = value; }, ), new TextFormField( decoration: new InputDecoration( contentPadding: EdgeInsets.only(left: 20,top: 10,right: 0,bottom: 0), hintText: '請輸入密碼', hintStyle: new TextStyle(fontSize: 30,color: Colors.amberAccent) ), obscureText: true, validator: (value){ return value.length < 6 ? '密碼長度不夠6位' : null; }, onSaved: (value){ userPwd = value; }, ) ], ), ), new Container( margin: new EdgeInsets.symmetric(vertical: 20,horizontal: 0), width: 330, height: 50, child: new SizedBox( child: new RaisedButton( onPressed: check, child: new Text( '肯定', style: new TextStyle( fontSize: 20, color: Colors.white ), ), ), ), ) ], ), ), ); } }
先看一下上面代碼的效果截圖,而後我會給你們講一下代碼的內容函數
寫的比較醜,你們見諒,主要是由於我想多試試一些屬性怎麼用,總之是要多嘗試嘛~佈局
上面是輸入內容前和輸入內容後的對比圖,從直觀的表象上能夠看的出來,用戶名輸入框輸入內容後,提示內容被擠到上面去了,而密碼輸入框輸入內容後提示內容則消失了,這是由於兩個輸入框提示語的text的類型使用的不一樣,用戶名:labelText,密碼:hintText,這兩個都有style屬性,均可以對默認的提示內容字體進行屬性設置。在點擊確認按鈕後,會調用check()方法,在check()方法中提交表單驗證,這時候會觸發密碼輸入框中的validator: (value),從而實現咱們密碼輸入框內容的校驗,這個就是TextFromField中的驗證回調方法,在表單驗證的時候,會先驗證這個方法中的邏輯判斷,若是驗證失敗返回錯誤信息,若是驗證經過則返回null。post
接下來的內容有興趣的能夠繼續看一下,我想以Android中寫xml的佈局方式理解一下Flutter中的頁面構建,由於我前面一直是在寫簡單的組件Demo,尚未造成一個完整的構建意識,如下是我我的的理解,若是有不對的地方,還請留言批評、指正,不勝感謝!!!學習
從整個頁面來構思的話,能夠看作是一個大容器,容器裏面有三個組件,分別是兩個輸入框和一個按鈕,這3個組件是垂直方向排列的,寫Android的同窗看到這個頁面,很容易就會想到最外層放一個Linearlayout或者是一個RelativeLayout,而後在裏面垂直方向放上兩個EditText和一個Button,再寫一下控件的屬性的就完事兒了,其實寫Flutter也是這種思想。字體
注:在這裏我先說明如下在Flutter中child裏面只能放一個Widget,Children能夠放多個Widget。ui
咱們來把Android和Flutter對比着理解,這樣應該能夠更容易理解一點,也更直觀一點:url
1.Android:最外層垂直方向的Linearlayout或RelativeLayout。
Flutter:最外層body咱們new了一個Column(Column也是一個容器,相似於Container)
2.Android:放上兩個EditText和一個Button
Flutter:容器放置好了,咱們要開始往容器裏面加組件元素了,由於容器裏面咱們要放置多個組件,因此咱們要使用children,children裏面放一個Form表單和一個button,在Form表單裏面,咱們要放兩個輸入框,並且是垂直方向放置的,想到這裏是否是就該先考慮怎麼把方向設置好呢?因此Form表單裏的第一層widget就要放置一個Column容器,容器裏面放兩個輸入框,既然是兩個,那麼是否是兩個輸入框就應該被一個children包裹起來呢?
總的來講:根widget(column)->children(裏面包含Form和button)->Form表單(第一層)->child(column)->children(裏面包含了兩個輸入框TextFormField)->TextFormField(第三層)
最後看一下按鈕部分的代碼,說明一下爲何外面要包一層Container
new Container( margin: new EdgeInsets.symmetric(vertical: 20,horizontal: 0), width: 330, height: 50, child: new SizedBox( child: new RaisedButton( onPressed: check, child: new Text( '肯定', style: new TextStyle( fontSize: 20, color: Colors.white ), ), ), ), )
之因此最外層包了個Container,是由於SizedBox和RaiseButton這兩個組件都沒有margin或padding屬性,因此UI上要想控制邊距等操做,這是一種處理方式。
也不知道我上面大白話寫了那麼多,能不能表達清楚個人意思,若是有沒看懂的,還麻煩留言提問吧!!!