表單組件是個包含表單元素的區域,表單元素允許用戶輸入內容,比如:文本區域,下拉表單,單選框、覆選框等,常見的應用場景有:登陸、註冊、輸入信息等。表單里有兩個重要的組件,一個是Form組件用來做整個表單提交使用的,另一個是TextFormField組件用來做用戶輸入的。 ...
如需轉載,請註明出處:Flutter學習筆記(13)--表單組件
表單組件是個包含表單元素的區域,表單元素允許用戶輸入內容,比如:文本區域,下拉表單,單選框、覆選框等,常見的應用場景有:登陸、註冊、輸入信息等。表單里有兩個重要的組件,一個是Form組件用來做整個表單提交使用的,另一個是TextFormField組件用來做用戶輸入的。
屬性 | 類型 | 說明 |
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的屬性,來獲取表單對象:
GlobalKey<FormState> globalKey = new GlobalKey<FormState>();
我們來簡單的寫一個登陸頁面,校驗輸入框內的內容,當內容不合法時,並給出相應的提示:
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。
接下來的內容有興趣的可以繼續看一下,我想以Android中寫xml的佈局方式理解一下Flutter中的頁面構建,因為我前面一直是在寫簡單的組件Demo,還沒有形成一個完整的構建意識,以下是我個人的理解,如果有不對的地方,還請留言批評、指正,不勝感謝!!!
從整個頁面來構思的話,可以看做是一個大容器,容器裡面有三個組件,分別是兩個輸入框和一個按鈕,這3個組件是垂直方向排列的,寫Android的同學看到這個頁面,很容易就會想到最外層放一個Linearlayout或者是一個RelativeLayout,然後在裡面垂直方向放上兩個EditText和一個Button,再寫一下控制項的屬性的就完事兒了,其實寫Flutter也是這種思想。
註:在這裡我先說明以下在Flutter中child裡面只能放一個Widget,Children可以放多個Widget。
我們來把Android和Flutter對比著理解,這樣應該可以更容易理解一點,也更直觀一點:
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上要想控制邊距等操作,這是一種處理方式。
也不知道我上面大白話寫了那麼多,能不能表達清楚我的意思,如果有沒看懂的,還麻煩留言提問吧!!!
下一章節:Flutter學習筆記(14)--App結構和導航組件