????這個章節(jié)本來打算講解Flutter的渲染原理,但是學(xué)習(xí)初期過多的講解原理性的內(nèi)容,并不利于大家快速入門和上手睦番,做出一些帶效果的內(nèi)容;
????所以耍属,我打算換一種思路托嚣,先講解一些組件的用法,讓大家習(xí)慣Flutter的開發(fā)過程和模式厚骗,再回頭去鞏固原理性的知識示启;
????另外,在講解這些Widget的時候领舰,我并不打算將所有的屬性一一列出夫嗓,因為沒有意義,也記不滋嶙帷啤月;
????我后面打算有一個專題是關(guān)于Flutter布局的,會選出一些好看的布局界面帶著大家一起來完成:美團頁面劳跃、京東頁面谎仲、B站頁面等等,某些我目前沒有講到的屬性刨仑,后面應(yīng)用的會再進(jìn)行講解
1. 文本W(wǎng)idget
在Android中郑诺,我們使用TextView,iOS中我們使用UILabel來顯示文本杉武;
Flutter中辙诞,我們使用Text組件控制文本如何展示;
1.1. 普通文本展示
在Flutter中轻抱,我們可以將文本的控制顯示分成兩類:
????控制文本布局的參數(shù): 如文本對齊方式 textAlign飞涂、文本排版方向 textDirection,文本顯示最大行數(shù) maxLines、文本截斷規(guī)則 overflow 等等较店,這些都是構(gòu)造函數(shù)中的參數(shù)士八;
????控制文本樣式的參數(shù): 如字體名稱 fontFamily、字體大小 fontSize梁呈、文本顏色 color婚度、文本陰影 shadows 等等,這些參數(shù)被統(tǒng)一封裝到了構(gòu)造函數(shù)中的參數(shù) style 中官卡;
下面我們來看一下其中一些屬性的使用:
class MyHomeBody extends StatelessWidget {
? @override
? Widget build(BuildContext context) {
? ? return Text(
? ? ? "《定風(fēng)波》 蘇軾 \n莫聽穿林打葉聲蝗茁,何妨吟嘯且徐行。\n竹杖芒鞋輕勝馬寻咒,誰怕哮翘?一蓑煙雨任平生。",
? ? ? style: TextStyle(
? ? ? ? fontSize: 20,
? ? ? ? color: Colors.purple
? ? ? ),
? ? );
? }
}
我們可以通過一些屬性來改變Text的布局:
????textAlign:文本對齊方式仔涩,比如TextAlign.center
????maxLines:最大顯示行數(shù)忍坷,比如1
????overflow:超出部分顯示方式,比如TextOverflow.ellipsis
????textScaleFactor:控制文本縮放熔脂,比如1.24
代碼如下:
class MyHomeBody extends StatelessWidget {
? @override
? Widget build(BuildContext context) {
? ? return Text(
? ? ? "《定風(fēng)波》 蘇軾 \n莫聽穿林打葉聲佩研,何妨吟嘯且徐行。\n竹杖芒鞋輕勝馬霞揉,誰怕旬薯?一蓑煙雨任平生。",
? ? ? textAlign: TextAlign.center, // 所有內(nèi)容都居中對齊
? ? ? maxLines: 3, // 顯然 "生适秩。" 被刪除了
? ? ? overflow: TextOverflow.ellipsis, // 超出部分顯示...
//? ? ? textScaleFactor: 1.25,
? ? ? style: TextStyle(
? ? ? ? fontSize: 20,
? ? ? ? color: Colors.purple
? ? ? ),
? ? );
? }
}
1.2. 富文本展示
前面展示的文本绊序,我們都應(yīng)用了相同的樣式,如果我們希望給他們不同的樣式呢秽荞?
????比如《定風(fēng)波》我希望字體更大一點骤公,并且是黑色字體,并且有加粗效果扬跋;
????比如 蘇軾 我希望是紅色字體阶捆;
如果希望展示這種混合樣式,那么我們可以利用分片來進(jìn)行操作(在Android中钦听,我們可以使用SpannableString洒试,在iOS中,我們可以使用NSAttributedString完成朴上,了解即可)
代碼如下:
class MyHomeBody extends StatelessWidget {
? @override
? Widget build(BuildContext context) {
? ? return Text.rich(
? ? ? TextSpan(
? ? ? ? children: [
? ? ? ? ? TextSpan(text: "《定風(fēng)波》", style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold, color: Colors.black)),
? ? ? ? ? TextSpan(text: "蘇軾", style: TextStyle(fontSize: 18, color: Colors.redAccent)),
? ? ? ? ? TextSpan(text: "\n莫聽穿林打葉聲垒棋,何妨吟嘯且徐行。\n竹杖芒鞋輕勝馬痪宰,誰怕叼架?一蓑煙雨任平生畔裕。")
? ? ? ? ],
? ? ? ),
? ? ? style: TextStyle(fontSize: 20, color: Colors.purple),
? ? ? textAlign: TextAlign.center,
? ? );
? }
}
二. 按鈕Widget
2.1. 按鈕的基礎(chǔ)
Material widget庫中提供了多種按鈕Widget如FloatingActionButton、RaisedButton碉碉、FlatButton柴钻、OutlineButton等
我們直接來對他們進(jìn)行一個展示:
class MyHomeBody extends StatelessWidget {
? @override
? Widget build(BuildContext context) {
? ? return Column(
? ? ? children: <Widget>[
? ? ? ? FloatingActionButton(
? ? ? ? ? child: Text("FloatingActionButton"),
? ? ? ? ? onPressed: () {
? ? ? ? ? ? print("FloatingActionButton Click");
? ? ? ? ? },
? ? ? ? ),
? ? ? ? RaisedButton(
? ? ? ? ? child: Text("RaisedButton"),
? ? ? ? ? onPressed: () {
? ? ? ? ? ? print("RaisedButton Click");
? ? ? ? ? },
? ? ? ? ),
? ? ? ? FlatButton(
? ? ? ? ? child: Text("FlatButton"),
? ? ? ? ? onPressed: () {
? ? ? ? ? ? print("FlatButton Click");
? ? ? ? ? },
? ? ? ? ),
? ? ? ? OutlineButton(
? ? ? ? ? child: Text("OutlineButton"),
? ? ? ? ? onPressed: () {
? ? ? ? ? ? print("OutlineButton Click");
? ? ? ? ? },
? ? ? ? )
? ? ? ],
? ? );
? }
}
2.2. 自定義樣式
前面的按鈕我們使用的都是默認(rèn)樣式淮韭,我們可以通過一些屬性來改變按鈕的樣式
RaisedButton(
? child: Text("同意協(xié)議", style: TextStyle(color: Colors.white)),
? color: Colors.orange, // 按鈕的顏色
? highlightColor: Colors.orange[700], // 按下去高亮顏色
? shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), // 圓角的實現(xiàn)
? onPressed: () {
? ? print("同意協(xié)議");
? },
)
事實上這里還有一個比較常見的屬性:elevation垢粮,用于控制陰影的大小,很多地方都會有這個屬性靠粪,大家可以自行演示一下
三. 圖片Widget
圖片可以讓我們的應(yīng)用更加豐富多彩蜡吧,F(xiàn)lutter中使用Image組件
Image組件有很多的構(gòu)造函數(shù),我們這里主要學(xué)習(xí)兩個:
????Image.assets:加載本地資源圖片占键;
????Image.network:加載網(wǎng)絡(luò)中的圖片昔善;
3.1. 加載網(wǎng)絡(luò)圖片
相對來講,F(xiàn)lutter中加載網(wǎng)絡(luò)圖片會更加簡單畔乙,直接傳入URL并不需要什么配置君仆,所以我們先來看一下Flutter中如何加載網(wǎng)絡(luò)圖片。
我們先來看看Image有哪些屬性可以設(shè)置:
const Image({
? ...
? this.width, //圖片的寬
? this.height, //圖片高度
? this.color, //圖片的混合色值
? this.colorBlendMode, //混合模式
? this.fit,//縮放模式
? this.alignment = Alignment.center, //對齊方式
? this.repeat = ImageRepeat.noRepeat, //重復(fù)方式
? ...
})
width牲距、height:用于設(shè)置圖片的寬返咱、高,當(dāng)不指定寬高時牍鞠,圖片會根據(jù)當(dāng)前父容器的限制咖摹,盡可能的顯示其原始大小,如果只設(shè)置width难述、height的其中一個萤晴,那么另一個屬性默認(rèn)會按比例縮放,但可以通過下面介紹的fit屬性來指定適應(yīng)規(guī)則胁后。
fit:該屬性用于在圖片的顯示空間和圖片本身大小不同時指定圖片的適應(yīng)模式店读。適應(yīng)模式是在BoxFit中定義,它是一個枚舉類型攀芯,有如下值:
????fill:會拉伸填充滿顯示空間屯断,圖片本身長寬比會發(fā)生變化,圖片會變形敲才。
????cover:會按圖片的長寬比放大后居中填滿顯示空間裹纳,圖片不會變形,超出顯示空間部分會被剪裁紧武。
????contain:這是圖片的默認(rèn)適應(yīng)規(guī)則剃氧,圖片會在保證圖片本身長寬比不變的情況下縮放以適應(yīng)當(dāng)前顯示空間,圖片不會變形阻星。
????fitWidth:圖片的寬度會縮放到顯示空間的寬度朋鞍,高度會按比例縮放已添,然后居中顯示,圖片不會變形滥酥,超出顯示空間部分會被剪裁更舞。
????fitHeight:圖片的高度會縮放到顯示空間的高度,寬度會按比例縮放坎吻,然后居中顯示缆蝉,圖片不會變形,超出顯示空間部分會被剪裁瘦真。
????none:圖片沒有適應(yīng)策略刊头,會在顯示空間內(nèi)顯示圖片,如果圖片比顯示空間大诸尽,則顯示空間只會顯示圖片中間部分原杂。
????color和 colorBlendMode:在圖片繪制時可以對每一個像素進(jìn)行顏色混合處理,color指定混合色您机,而colorBlendMode指定混合模式穿肄;
????repeat:當(dāng)圖片本身大小小于顯示空間時,指定圖片的重復(fù)規(guī)則际看。
我們對其中某些屬性做一個演練:
????注意咸产,這里我用了一個Container,大家可以把它理解成一個UIView或者View仿村,就是一個容器锐朴;
????后面我會專門講到這個組件的使用;
class MyHomeBody extends StatelessWidget {
? @override
? Widget build(BuildContext context) {
? ? return Center(
? ? ? child: Container(
? ? ? ? child: Image.network(
? ? ? ? ? ? ? ? ? ? ? ?????????????????????"http://img0.dili360.com/ga/M01/48/3C/wKgBy1kj49qAMVd7ADKmuZ9jug8377.tub.jpg",
? ? ? ? ? alignment: Alignment.topCenter,
? ? ? ? ? repeat: ImageRepeat.repeatY,
? ? ? ? ? color: Colors.red,
? ? ? ? ? colorBlendMode: BlendMode.colorDodge,
? ? ? ? ),
? ? ? ? width: 300,
? ? ? ? height: 300,
? ? ? ? color: Colors.yellow,
? ? ? ),
? ? );
? }
}
3.2. 加載本地圖片
加載本地圖片稍微麻煩一點蔼囊,需要將圖片引入焚志,并且進(jìn)行配置
class MyHomeBody extends StatelessWidget {
? @override
? Widget build(BuildContext context) {
? ? return Center(
? ? ? child: Container(
? ? ? ? width: 300,
? ? ? ? height: 300,
? ? ? ? color: Colors.yellow,
? ? ? ? child: Image.asset("images/test.jpeg"),
? ? ? ),
? ? );
? }
}
3.3. 實現(xiàn)圓角圖像
在Flutter中實現(xiàn)圓角效果也是使用一些Widget來實現(xiàn)的。
3.3.1. 實現(xiàn)圓角頭像
方式一:CircleAvatar
CircleAvatar可以實現(xiàn)圓角頭像畏鼓,也可以添加一個子Widget:
const CircleAvatar({
? Key key,
? this.child, // 子Widget
? this.backgroundColor, // 背景顏色
? this.backgroundImage, // 背景圖像
? this.foregroundColor, // 前景顏色
? this.radius, // 半徑
? this.minRadius, // 最小半徑
? this.maxRadius, // 最大半徑
})
我們來實現(xiàn)一個圓形頭像:
????注意一:這里我們使用的是NetworkImage酱酬,因為backgroundImage要求我們傳入一個ImageProvider;
????????ImageProvider是一個抽象類云矫,事實上所有我們前面創(chuàng)建的Image對象都有包含image屬性膳沽,該屬性就是一個ImageProvider
????注意二:這里我還在里面添加了一個文字,但是我在文字外層包裹了一個Container让禀;
????????這里Container的作用是為了可以控制文字在其中的位置調(diào)整挑社;
class HomeContent extends StatelessWidget {
? @override
? Widget build(BuildContext context) {
? ? return Center(
? ? ? child: CircleAvatar(
? ? ? ? radius: 100,
? ? ? ? backgroundImage: NetworkImage("https://tva1.sinaimg.cn/large/006y8mN6gy1g7aa03bmfpj3069069mx8.jpg"),
? ? ? ? child: Container(
? ? ? ? ? alignment: Alignment(0, .5),
? ? ? ? ? width: 200,
? ? ? ? ? height: 200,
? ? ? ? ? child: Text("兵長利威爾")
? ? ? ? ),
? ? ? ),
? ? );
? }
}
方式二:ClipOval
ClipOval也可以實現(xiàn)圓角頭像,而且通常是在只有頭像時使用
class HomeContent extends StatelessWidget {
? @override
? Widget build(BuildContext context) {
? ? return Center(
? ? ? child: ClipOval(
? ? ? ? child: Image.network(
? ? ? ? ? "https://tva1.sinaimg.cn/large/006y8mN6gy1g7aa03bmfpj3069069mx8.jpg",
? ? ? ? ? width: 200,
? ? ? ? ? height: 200,
? ? ? ? ),
? ? ? ),
? ? );
? }
}
實現(xiàn)方式三:Container+BoxDecoration
這種方式我們放在講解Container時來講這種方式
3.3.2. 實現(xiàn)圓角圖片
方式一:ClipRRect
ClipRRect用于實現(xiàn)圓角效果巡揍,可以設(shè)置圓角的大小痛阻。
實現(xiàn)代碼如下,非常簡單:
class HomeContent extends StatelessWidget {
? @override
? Widget build(BuildContext context) {
? ? return Center(
? ? ? child: ClipRRect(
? ? ? ? borderRadius: BorderRadius.circular(10),
? ? ? ? child: Image.network(
? ? ? ? ? "https://tva1.sinaimg.cn/large/006y8mN6gy1g7aa03bmfpj3069069mx8.jpg",
? ? ? ? ? width: 200,
? ? ? ? ? height: 200,
? ? ? ? ),
? ? ? ),
? ? );
? }
}
方式二:Container+BoxDecoration
這個也放到后面講解Container時講解
四. 表單Widget
和用戶交互的其中一種就是輸入框腮敌,比如注冊阱当、登錄俏扩、搜索,我們收集用戶輸入的內(nèi)容將其提交到服務(wù)器弊添。
4.1. TextField的使用
4.1.1. TextField的介紹
TextField用于接收用戶的文本輸入录淡,它提供了非常多的屬性,我們來看一下源碼:
????但是我們沒必要一個個去學(xué)習(xí)油坝,很多時候用到某個功能時去查看是否包含某個屬性即可
const TextField({
? Key key,
? this.controller,
? this.focusNode,
? this.decoration = const InputDecoration(),
? TextInputType keyboardType,
? this.textInputAction,
? this.textCapitalization = TextCapitalization.none,
? this.style,
? this.strutStyle,
? this.textAlign = TextAlign.start,
? this.textAlignVertical,
? this.textDirection,
? this.readOnly = false,
? ToolbarOptions toolbarOptions,
? this.showCursor,
? this.autofocus = false,
? this.obscureText = false,
? this.autocorrect = true,
? this.maxLines = 1,
? this.minLines,
? this.expands = false,
? this.maxLength,
? this.maxLengthEnforced = true,
? this.onChanged,
? this.onEditingComplete,
? this.onSubmitted,
? this.inputFormatters,
? this.enabled,
? this.cursorWidth = 2.0,
? this.cursorRadius,
? this.cursorColor,
? this.keyboardAppearance,
? this.scrollPadding = const EdgeInsets.all(20.0),
? this.dragStartBehavior = DragStartBehavior.start,
? this.enableInteractiveSelection = true,
? this.onTap,
? this.buildCounter,
? this.scrollController,
? this.scrollPhysics,
})
我們來學(xué)習(xí)幾個比較常見的屬性:
????一些屬性比較簡單:keyboardType鍵盤的類型嫉戚,style設(shè)置樣式,textAlign文本對齊方式免钻,maxLength最大顯示行數(shù)等等彼水;
decoration:用于設(shè)置輸入框相關(guān)的樣式
????icon:設(shè)置左邊顯示的圖標(biāo)
????labelText:在輸入框上面顯示一個提示的文本
????hintText:顯示提示的占位文字
????border:輸入框的邊框,默認(rèn)底部有一個邊框极舔,可以通過InputBorder.none刪除掉
????filled:是否填充輸入框,默認(rèn)為false
????fillColor:輸入框填充的顏色
controller:
onChanged:監(jiān)聽輸入框內(nèi)容的改變链瓦,傳入一個回調(diào)函數(shù)
onSubmitted:點擊鍵盤中右下角的down時拆魏,會回調(diào)的一個函數(shù)
4.1.2. TextField的樣式以及監(jiān)聽
我們來演示一下TextField的decoration屬性以及監(jiān)聽:
class HomeContent extends StatelessWidget {
? @override
? Widget build(BuildContext context) {
? ? return Container(
? ? ? padding: EdgeInsets.all(20),
? ? ? child: Column(
? ? ? ? mainAxisAlignment: MainAxisAlignment.center,
? ? ? ? children: <Widget>[
? ? ? ? ? TextFieldDemo()
? ? ? ? ],
? ? ? ),
? ? );
? }
}
class TextFieldDemo extends StatefulWidget {
? @override
? _TextFieldDemoState createState() => _TextFieldDemoState();
}
class _TextFieldDemoState extends State<TextFieldDemo> {
? @override
? Widget build(BuildContext context) {
? ? return TextField(
? ? ? decoration: InputDecoration(
? ? ? ? icon: Icon(Icons.people),
? ? ? ? labelText: "username",
? ? ? ? hintText: "請輸入用戶名",
? ? ? ? border: InputBorder.none,
? ? ? ? filled: true,
? ? ? ? fillColor: Colors.lightGreen
? ? ? ),
? ? ? onChanged: (value) {
? ? ? ? print("onChanged:$value");
? ? ? },
? ? ? onSubmitted: (value) {
? ? ? ? print("onSubmitted:$value");
? ? ? },
? ? );
? }
}
4.1.3. TextField的controller
????我們可以給TextField添加一個控制器(Controller),可以使用它設(shè)置文本的初始值慈俯,也可以使用它來監(jiān)聽文本的改變渤刃;
????事實上,如果我們沒有為TextField提供一個Controller贴膘,那么會Flutter會默認(rèn)創(chuàng)建一個TextEditingController的卖子,這個結(jié)論可以通過閱讀源碼得到:
@override
? void initState() {
? ? super.initState();
? ? // ...其他代碼
? ? if (widget.controller == null)
? ? ? _controller = TextEditingController();
? }
我們也可以自己來創(chuàng)建一個Controller控制一些內(nèi)容:
class _TextFieldDemoState extends State<TextFieldDemo> {
? final textEditingController = TextEditingController();
? @override
? void initState() {
? ? super.initState();
? ? // 1.設(shè)置默認(rèn)值
? ? textEditingController.text = "Hello World";
? ? // 2.監(jiān)聽文本框
? ? textEditingController.addListener(() {
? ? ? print("textEditingController:${textEditingController.text}");
? ? });
? }
? // ...省略build方法
}
4.2. Form表單的使用
????在我們開發(fā)注冊、登錄頁面時刑峡,通常會有多個表單需要同時獲取內(nèi)容或者進(jìn)行一些驗證洋闽,如果對每一個TextField都分別進(jìn)行驗證,是一件比較麻煩的事情突梦。
????做過前端的開發(fā)知道诫舅,我們可以將多個input標(biāo)簽放在一個form里面,F(xiàn)lutter也借鑒了這樣的思想:我們可以通過Form對輸入框進(jìn)行分組宫患,統(tǒng)一進(jìn)行一些操作刊懈。
4.2.1. Form表單的基本使用
Form表單也是一個Widget,可以在里面放入我們的輸入框娃闲。
但是Form表單中輸入框必須是FormField類型的
????我們查看剛剛學(xué)過的TextField是繼承自StatefulWidget虚汛,并不是一個FormField類型;
????我們可以使用TextFormField皇帮,它的使用類似于TextField卷哩,并且是繼承自FormField的;
我們通過Form的包裹玲献,來實現(xiàn)一個注冊的頁面:
class FormDemo extends StatefulWidget {
? @override
? _FormDemoState createState() => _FormDemoState();
}
class _FormDemoState extends State<FormDemo> {
? @override
? Widget build(BuildContext context) {
? ? return Form(
? ? ? child: Column(
? ? ? ? mainAxisAlignment: MainAxisAlignment.center,
? ? ? ? children: <Widget>[
? ? ? ? ? TextFormField(
? ? ? ? ? ? decoration: InputDecoration(
? ? ? ? ? ? ? icon: Icon(Icons.people),
? ? ? ? ? ? ? labelText: "用戶名或手機號"
? ? ? ? ? ? ),
? ? ? ? ? ),
? ? ? ? ? TextFormField(
? ? ? ? ? ? obscureText: true,
? ? ? ? ? ? decoration: InputDecoration(
? ? ? ? ? ? ? icon: Icon(Icons.lock),
? ? ? ? ? ? ? labelText: "密碼"
? ? ? ? ? ? ),
? ? ? ? ? ),
? ? ? ? ? SizedBox(height: 16,),
? ? ? ? ? Container(
? ? ? ? ? ? width: double.infinity,
? ? ? ? ? ? height: 44,
? ? ? ? ? ? child: RaisedButton(
? ? ? ? ? ? ? color: Colors.lightGreen,
? ? ? ? ? ? ? child: Text("注 冊", style: TextStyle(fontSize: 20, color: Colors.white),),
? ? ? ? ? ? ? onPressed: () {
? ? ? ? ? ? ? ? print("點擊了注冊按鈕");
? ? ? ? ? ? ? },
? ? ? ? ? ? ),
? ? ? ? ? )
? ? ? ? ],
? ? ? ),
? ? );
? }
}
4.2.2. 保存和獲取表單數(shù)據(jù)
有了表單后殉疼,我們需要在點擊注冊時梯浪,可以同時獲取和保存表單中的數(shù)據(jù),怎么可以做到呢瓢娜?
????1挂洛、需要監(jiān)聽注冊按鈕的點擊,在之前我們已經(jīng)監(jiān)聽的onPressed傳入的回調(diào)中來做即可眠砾。(當(dāng)然虏劲,如果嵌套太多,我們待會兒可以將它抽取到一個單獨的方法中)
????2褒颈、監(jiān)聽到按鈕點擊時柒巫,同時獲取用戶名和密碼的表單信息。
如何同時獲取用戶名和密碼的表單信息谷丸?
????如果我們調(diào)用Form的State對象的save方法堡掏,就會調(diào)用Form中放入的TextFormField的onSave回調(diào):
TextFormField(
? decoration: InputDecoration(
? ? icon: Icon(Icons.people),
? ? labelText: "用戶名或手機號"
? ),
? onSaved: (value) {
? ? print("用戶名:$value");
? },
),
????但是,我們有沒有辦法可以在點擊按鈕時刨疼,拿到 Form對象 來調(diào)用它的save方法呢泉唁?
知識點:在Flutter如何可以獲取一個通過一個引用獲取一個StatefulWidget的State對象呢?
答案:通過綁定一個GlobalKey即可揩慕。
案例代碼演練:
class FormDemo extends StatefulWidget {
? @override
? _FormDemoState createState() => _FormDemoState();
}
class _FormDemoState extends State<FormDemo> {
? final registerFormKey = GlobalKey<FormState>();
? String username, password;
? void registerForm() {
? ? registerFormKey.currentState.save();
? ? print("username:$username password:$password");
? }
? @override
? Widget build(BuildContext context) {
? ? return Form(
? ? ? key: registerFormKey,
? ? ? child: Column(
? ? ? ? mainAxisAlignment: MainAxisAlignment.center,
? ? ? ? children: <Widget>[
? ? ? ? ? TextFormField(
? ? ? ? ? ? decoration: InputDecoration(
? ? ? ? ? ? ? icon: Icon(Icons.people),
? ? ? ? ? ? ? labelText: "用戶名或手機號"
? ? ? ? ? ? ),
? ? ? ? ? ? onSaved: (value) {
? ? ? ? ? ? ? this.username = value;
? ? ? ? ? ? },
? ? ? ? ? ),
? ? ? ? ? TextFormField(
? ? ? ? ? ? obscureText: true,
? ? ? ? ? ? decoration: InputDecoration(
? ? ? ? ? ? ? icon: Icon(Icons.lock),
? ? ? ? ? ? ? labelText: "密碼"
? ? ? ? ? ? ),
? ? ? ? ? ? onSaved: (value) {
? ? ? ? ? ? ? this.password = value;
? ? ? ? ? ? },
? ? ? ? ? ),
? ? ? ? ? SizedBox(height: 16,),
? ? ? ? ? Container(
? ? ? ? ? ? width: double.infinity,
? ? ? ? ? ? height: 44,
? ? ? ? ? ? child: RaisedButton(
? ? ? ? ? ? ? color: Colors.lightGreen,
? ? ? ? ? ? ? child: Text("注 冊", style: TextStyle(fontSize: 20, color: Colors.white),),
? ? ? ? ? ? ? onPressed: registerForm,
? ? ? ? ? ? ),
? ? ? ? ? )
? ? ? ? ],
? ? ? ),
? ? );
? }
}
4.2.3. 驗證填寫的表單數(shù)據(jù)
在表單中亭畜,我們可以添加驗證器,如果不符合某些特定的規(guī)則迎卤,那么給用戶一定的提示信息
比如我們需要賬號和密碼有這樣的規(guī)則:賬號和密碼都不能為空拴鸵。
按照如下步驟就可以完成整個驗證過程:
????1、為TextFormField添加validator的回調(diào)函數(shù)蜗搔;
????2劲藐、調(diào)用Form的State對象的validate方法,就會回調(diào)validator傳入的函數(shù)碍扔;
也可以為TextFormField添加一個屬性:autovalidate
????不需要調(diào)用validate方法瘩燥,會自動驗證是否符合要求;