前言
拖了好久終于開(kāi)始看Flutter,為了加深印象鞏固學(xué)習(xí)效果,現(xiàn)將每次學(xué)習(xí)的內(nèi)容總結(jié)成筆記,鞏固效果也方便以后查閱。同時(shí),筆記相關(guān)的Demo項(xiàng)目已經(jīng)上傳到Github,這里是傳送門(mén),歡迎指正。
正文
Flutter相關(guān)文檔
1.官方文檔
2.Flutter中文網(wǎng)
3.官方Demo(Github地址)
基礎(chǔ)控件目錄
常用基礎(chǔ)控件
不管在哪個(gè)前端平臺(tái),常用的基礎(chǔ)控件都一樣,大致包括:文本、圖片、按鈕、輸入框、進(jìn)度條、單選框和復(fù)選框、開(kāi)關(guān)切換(Switch)、提示窗、對(duì)話框;布局用的控件(Layout)基本包含:橫向布局、縱向布局、格子布局、重疊布局、各類(lèi)包含不同約束條件的特定布局(內(nèi)外間距,靠邊居中,相對(duì)位置等);然后是一些根據(jù)常用程度封裝的控件包括:列表控件、滑動(dòng)控件(橫縱方向),下拉刷新,抽屜(Drawer)等。
然后在Flutter中,控件分為StatefulWidget和StatelessWidget(有狀態(tài)控件和無(wú)狀態(tài)控件),無(wú)狀態(tài)控件是死的,不會(huì)動(dòng)態(tài)更新,所以實(shí)際使用的時(shí)候大多數(shù)情況下都是封裝自己的StatefulWidget,StatefulWidget的狀態(tài)存儲(chǔ)在對(duì)應(yīng)的State類(lèi)里面,需要更新的時(shí)候可以通過(guò)調(diào)用setState()方法來(lái)刷新頁(yè)面。
StatefulWidget基本代碼模板如下:
class DemoStatefulWidget extends StatefulWidget{
@override
State<StatefulWidget> createState() {
return DemoState();
}
}
class DemoState extends State<DemoStatefulWidget>{
var data;
@override
Widget build(BuildContext context) {
return Text(data);
}
void onDataChanged(newData){
setState(() {//刷新控件
data = newData;
});
}
}
接下來(lái),按照上面梳理出的常用控件,我們一個(gè)一個(gè)來(lái)看。
文本 Text
Text官方文檔
沒(méi)啥注意點(diǎn),屬性看文檔基本都能看懂。
基本使用
Widget build(BuildContext context) {
return new Text(
"A text in container",
style: new TextStyle(
color: Color(0xFF0000CD), fontStyle: FontStyle.normal, fontSize: 15),
);
}
圖片 Image
Image官方文檔
也沒(méi)啥注意點(diǎn)。
基本使用
Widget build(BuildContext context) {
return Image.network(//圖片來(lái)自網(wǎng)絡(luò)
imageUrl,
width: 200.0,
height: 150.0,
);
// Image.asset(name);//圖片來(lái)自項(xiàng)目?jī)?nèi)的資源
// Image.file(file);//圖片來(lái)自文件
// Image.memory(bytes);//圖片來(lái)自內(nèi)存
}
按鈕 RaisedButton FlatButton
這兩個(gè)按鈕除了風(fēng)格不同以外沒(méi)什么別的區(qū)別,只有個(gè)別屬性彼此有區(qū)分。
RaisedButton官方文檔
FlatButton官方文檔
Widget build(BuildContext context) {
return RaisedButton(
elevation: 5,
color: Color(0xff87CEFA),
child: Text("Print"),
onPressed: () {}
);
}
輸入框 TextField
TextField官方文檔
基本使用
Widget build(BuildContext context) {
return TextField(
maxLines: 5,
style: TextStyle(color: Colors.black),
controller: editController,
obscureText: false,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Text',
)
);
進(jìn)度條 Slider
Slider官方文檔
注意點(diǎn):
dividions屬性,比如設(shè)置dividions屬性為4,進(jìn)度條被分為四等分,滑動(dòng)時(shí)進(jìn)度會(huì)停留在等分點(diǎn)上;
label屬性,設(shè)置之后,滑動(dòng)時(shí),標(biāo)簽將展示在進(jìn)度條上;
效果如下:

代碼:
Widget build(BuildContext context) {
return Slider(
label: 'slider',
value: rating,
divisions: 4,
onChanged: (newValue) {
setState(() {
rating = newValue;
});
print('rating: ${rating}'); //打日志到控制臺(tái))
},
);
CheckBox
很簡(jiǎn)單沒(méi)啥要注意的。
CheckBox官方文檔
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.fromLTRB(0.0, 10, 0, 10),
margin: EdgeInsets.fromLTRB(0, 10, 15, 10),
alignment: Alignment(-1, 0),
//min和max為最小進(jìn)度值和最大進(jìn)度值,不設(shè)置的話默認(rèn)為0到1
child: Slider(
inactiveColor: Colors.cyan[100],
activeColor: Colors.cyan[400],
min: 0,
max: 2,
label: 'slider',
value: rating,
onChanged: (newValue) {
setState(() {
rating = newValue;
});
print('rating1: ${rating}'); //打日志到控制臺(tái))
},
),
);
}
Radio
Radio官方文檔
這個(gè)看文檔有點(diǎn)迷糊,而且這個(gè)使用和Android的不一樣。
這里要注意的是value和groupValue兩個(gè)屬性,value是當(dāng)這個(gè)Radio選中的時(shí)候更新到onChange方法里的值,groupValue是,當(dāng)它的值和value的值相同時(shí),這個(gè)Radio就是選中狀態(tài),否則就是非選中狀態(tài)。所以一般使用時(shí)都是把groupValue的值設(shè)定為一個(gè)動(dòng)態(tài)變量,然后在onChange方法里更新這個(gè)動(dòng)態(tài)變量。
基本使用
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
//靠左
verticalDirection: VerticalDirection.down,
children: <Widget>[
Container(
margin: EdgeInsets.fromLTRB(0, 10, 15, 0),
child:
Text('Radio:')),
Row(
children: <Widget>[
Text('1'),
Radio(
value: '1',
groupValue: this.radioSelectedPosition,
onChanged: (radioChange) {
setState(() {
this.radioSelectedPosition = radioChange;
});
print('radioChange1: ${radioChange}'); //打日志到控制臺(tái))
},
),
],
),
Row(
children: <Widget>[
Text('2'),
Radio(
value:'2',
groupValue: this.radioSelectedPosition,
onChanged: (radioChange) {
setState(() {
this.radioSelectedPosition = radioChange;
});
print('radioChange2: ${radioChange}'); //打日志到控制臺(tái))
},
),
],
),
Row(
children: <Widget>[
Text('3'),
Radio<String>(
value: '3',
groupValue: this.radioSelectedPosition,
onChanged: (radioChange) {
setState(() {
this.radioSelectedPosition = radioChange;
});
print('radioChange3: ${radioChange}'); //打日志到控制臺(tái))
},
),
],
),
]);
}
效果:

Switch
Widget build(BuildContext context) {
return Switch(
activeColor: Colors.deepOrange[300],
activeTrackColor: Colors.deepOrange[600],
inactiveTrackColor: Colors.blue[300],
inactiveThumbColor: Colors.blue[100],
inactiveThumbImage: NetworkImage(imageUrl),
value: switchOn,
onChanged: (switchOn){
setState(() {
this.switchOn = switchOn;
print('switchOn: ${switchOn}'); //打日志到控制臺(tái))
});
},
);
}
最后,有一個(gè)重要而且特別的屬性
在看第一個(gè)控件的時(shí)候,我就注意到這個(gè)屬性,key,排在第一位。簡(jiǎn)單看文檔看不明白到底是做什么用的,然后往下看的時(shí)候我注意到每一個(gè)控件都有key這個(gè)屬性,而且都是排在第一位。于是我去查看了官方文檔,結(jié)果我的個(gè)乖乖,開(kāi)頭就是一個(gè)整整10分鐘的講解視頻,由于視頻是全英文的并且字幕翻譯的并不好,我反復(fù)看了三遍,才大致摸清楚了key的含義和用法。
要理解這個(gè)key的使用必須要對(duì)Flutter的控件樹(shù)刷新機(jī)制有簡(jiǎn)單的了解。Flutter在構(gòu)建Widget樹(shù)的時(shí)候,同時(shí)會(huì)構(gòu)建一個(gè)Element樹(shù),這個(gè)Element樹(shù)才是顯示和刷新頁(yè)面的時(shí)候真正起作用的東西,Widget里面只是存了一些控件的屬性值而已。在刷新Element樹(shù)的時(shí)候,F(xiàn)lutter會(huì)依次對(duì)比每個(gè)控件的改變狀態(tài),首先是檢查type,如果兩個(gè)控件是相同的類(lèi)型,type就是一樣的,然后是檢查key,比如你交換了頁(yè)面中兩個(gè)Text的位置,改變了Widget樹(shù)的結(jié)構(gòu),如果此時(shí)你對(duì)這個(gè)控件設(shè)置了key,它會(huì)檢查出前后狀態(tài)下控件的key不一樣,會(huì)判定這里有修改,然后Flutter會(huì)去遍歷和刷新Element樹(shù),將它調(diào)整到正確的交換后的狀態(tài),否則的話,由于兩個(gè)Text的type是一樣的,F(xiàn)lutter檢查之后會(huì)認(rèn)為Element樹(shù)沒(méi)有必要刷新,此時(shí)就會(huì)出現(xiàn)錯(cuò)誤,你會(huì)發(fā)現(xiàn)你交換控件之后頁(yè)面上兩個(gè)文本沒(méi)有絲毫改變,如果你不了解這個(gè)機(jī)制的話,這個(gè)錯(cuò)誤會(huì)顯得莫名其妙并且完全摸不著頭腦。
然后,key還包括ValueKey、LocalKey、GlobleKey,各種場(chǎng)景下適合使用的類(lèi)型不相同,詳細(xì)可見(jiàn)官方文檔。然后后來(lái)找到一篇文章,基本很詳細(xì)的把官方視頻要闡述的內(nèi)容解釋清楚了,好文傳送門(mén)。
尾聲
以上,第一部分暫時(shí)整理這么多,接下來(lái)空余時(shí)間再逐步梳理剩下的控件,預(yù)計(jì)整個(gè)常用控件的梳理大概要分3篇筆記。個(gè)人從零逐步學(xué)習(xí)Flutter,水平有限,如發(fā)現(xiàn)問(wèn)題,歡迎斧正!