文章目錄
到這章我們就差不多可以開始寫天氣預報了。首先我們來看一下一些基礎簡單的Widget。
1. 基礎組件
1.1 文本
Text
用於顯示簡單的文本,包含一些控制文本顯示的屬性。
Text(
"1234",
),
Text(
"1234",
style: TextStyle(
color: Colors.purple,
fontSize: 32.0,
fontWeight: FontWeight.bold,
),
),
- 需要顯示的文本信息直接放到一個雙引號裏面就可以了;
textAlign
:文本對齊方式;maxLines
:文本顯示的最大行數;overflow
:指定多餘文本的截斷方式;textScaleFactor
:指定文本相對於當前字體大小的縮放因子;TextStyle
:設置顯示文本的字體、顏色、粗細等樣式:height
:指定行高,但是不是絕對值,而是一個因子,相當於fontsize * height
;fontFamily
:設置字體;fontSize
:設置字體大小
1.2 按鈕
不同的組件庫有不同的按鈕,我們現在只拿Material組件庫中的按鈕舉例。
RaisedButton
漂浮按鈕,帶有陰影和灰色背景。按下後陰影會變大。
RaisedButton(
child: Text("1234"),
onPressed: () {},
);
FlatButton
扁平化按鈕,背景透明且不帶陰影,按下後會有背景色。
FlatButton(
child: Text("1234"),
onPressed: () {},
)
IconButton
可點擊的Icon,默認沒有背景,按下後出現陰影
IconButton(
icon: Icon(Icons.thumb_up),
onPressed: () {},
)
1.3 圖片
我們通過Image
來顯示圖片,來源可以是asset
、網絡等位置。
從asset加載圖片
- 現在項目根目錄(也就是和android、ios、lib等目錄同級)新建一個
images
目錄,並把圖片main.png
拷進去; - 在
pubspec.yaml
中的flutter部分添加一下內容:
- 加載該圖片
Image(
image: AssetImage("images/amoled.png"),
);
Image
也提供了一個快速構造函數:
Image.asset(
"images/amoled.png",
)
從網絡加載圖片
Image(
image: NetworkImage(
"https://s2.ax1x.com/2019/05/27/VZrQ3V.png"),
)
或者
Image.network(
"https://s2.ax1x.com/2019/05/27/VZrQ3V.png",
)
參數
Image
有一些基本參數
const Image({
...
this.width, //圖片的寬
this.height, //圖片高度
this.fit,//縮放模式
this.alignment = Alignment.center, //對齊方式
this.repeat = ImageRepeat.noRepeat, //重複方式
...
})
width
和height
:寬和高;fit
:縮放模式:fill
:拉伸圖片知道填滿;cover
:按原圖長寬比放大圖片來填滿,多餘的部分捨去;contain
:在保證圖片長寬比不變的情況下儘可能去填滿;fitWidth
:寬度會縮放到顯示空間的寬度,高度會按比例縮放,如果有多餘的部分會被捨去;fitHeight
:與fitWidth
同理;none
:沒有適應策略,圖片多大就顯示多大,如果圖片原尺寸小於顯示空間就只顯示原尺寸;如果大於則捨棄多餘部分只顯示中間部分;
repeat
:當圖片小於顯示空間時,會將圖片重複顯示。
2. 佈局組件
2.1 線性佈局(Row、Column)
線性佈局就相當於Android裏面的LinearLayout
,但是不同的是Flutter將豎直和水平佈局單獨拿了出來。
線性佈局分爲豎直佈局Column
和水平佈局Row
。他兩屬性都是一樣的。
再說屬性之前我們先熟悉兩個概念:主軸和交叉軸。如果是Column
,主軸是豎直軸,交叉軸是水平軸;如果是Row
,主軸是水平軸,交叉軸是豎直軸。
Row({
...
MainAxisSize mainAxisSize = MainAxisSize.max,
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
List<Widget> children = const <Widget>[],
})
mainAxisSize
:主軸佔用空間。默認是MainAxisSize.max
,是指佔用全部主軸空間。如果設置爲MainAxisSize.min
,那就只佔用所有子組件所需要的空間;mainAxisAlignment
:子Widget在主軸的對其方向;crossAxisAlignment
:子Widget在交叉軸的對其方向;children
:所有的子Widget。
2.2 彈性佈局(Flex)
其實這個佈局和線性佈局很有淵源,爲什麼這麼說呢,因爲Row
和Column
都繼承自它。
因此關於他和線性佈局重複的地方我們現在就不再講了,我們直說他“彈性”的部分。
Expanded
可以按比例“拉伸”Row
、Column
和Flex
子組件所佔的空間。
const Expanded({
int flex = 1,
@required Widget child,
})
flex
爲彈性係數,如果爲0
或者null
,則child
不會闊伸佔用的控件。如果大於0
,則會按照flex
的比例來分隔主軸全部空閒空間。其實說白了,就和Android裏面LinearLayout
的weight
一樣的。但是我們還是來舉個例子吧。
return Scaffold(
appBar: new AppBar(
title: Text("$_title"),
),
body: Center(
child: Flex(
children: <Widget>[
Flex(
direction: Axis.horizontal,
children: <Widget>[
Expanded(
flex: 1,
child: Container(
color: Colors.blue,
child: Text("1234"),
),
),
Expanded(
flex: 2,
child: Container(
color: Colors.red,
child: Text("1234"),
),
),
],
),
Flex(
direction: Axis.horizontal,
children: <Widget>[
Expanded(
flex: 3,
child: Container(
color: Colors.blue,
child: Text("1234"),
),
),
Expanded(
flex: 1,
child: Container(
color: Colors.red,
child: Text("1234"),
),
),
],
),
Flex(
direction: Axis.horizontal,
children: <Widget>[
Expanded(
flex: 1,
child: Container(
color: Colors.blue,
child: Text("1234"),
),
),
Expanded(
flex: 1,
child: Container(
color: Colors.red,
child: Text("1234"),
),
),
],
),
],
direction: Axis.vertical,
),
),
);
2.3流式佈局(Wrap、Flow)
如果使用線性佈局的話,當需要顯示的內容超出屏幕邊界的時候就會報錯。
爲了避免這種情況,我們就可以使用流式佈局。當需要顯示的內容超出屏幕邊界的時候,就自動折行來繼續顯示。
Flutter中通過Wrap
和Flow
來實現流式佈局。
Wrap
我們來看下Wrap
主要的一些參數:
Wrap({
...
this.direction = Axis.horizontal,
this.alignment = WrapAlignment.start,
this.spacing = 0.0,
this.runAlignment = WrapAlignment.start,
this.runSpacing = 0.0,
this.crossAxisAlignment = WrapCrossAlignment.start,
this.textDirection,
this.verticalDirection = VerticalDirection.down,
List<Widget> children = const <Widget>[],
})
其中很多參數Row
和Column
中都有,就不再介紹了,主要介紹點不同的:
spacing
:主軸方向子widget的間距runSpacing
:縱軸方向的間距runAlignment
:縱軸方向的對齊方式
下面有一個示例:
Wrap(
spacing: 8.0, // 主軸(水平)方向間距
runSpacing: 4.0, // 縱軸(垂直)方向間距
alignment: WrapAlignment.center, //沿主軸方向居中
children: <Widget>[
new Chip(
avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('A')),
label: new Text('Hamilton'),
),
new Chip(
avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('M')),
label: new Text('Lafayette'),
),
new Chip(
avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('H')),
label: new Text('Mulligan'),
),
new Chip(
avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('J')),
label: new Text('Laurens'),
),
],
)
Flow
Flow
較複雜,需要自己實現子Widget的位置轉換,一般不推薦使用Flow
。但是如果需要自定義佈局策略,或者對性能要求較高,這個時候就得用Flow
了。
但是由於太過於複雜,我也沒咋用過,我就不在這講了?,大家有需要的可以百度,或者看我推薦的這篇:4.4 流式佈局-《Flutter實戰》
2.4層疊佈局(Stack)
這個佈局類似於Android中的Frame
,允許在父佈局的任意地方放置佈局。
Stack({
this.alignment = AlignmentDirectional.topStart,
this.textDirection,
this.fit = StackFit.loose,
this.overflow = Overflow.clip,
List<Widget> children = const <Widget>[],
})
alignment
:決定如何去對齊;textDirection
:確定alignment
的參考系;fit
:沒有定位的子Widget如何去適應Stack
的大小;overflow
:決定超出Stack
顯示空間的子Widget如何去顯示,如果Overflow.clip
,則超出部分會隱藏,Overflow.visible
則不會。
2.5對齊與相對定位(Align)
Align可以調整子Widget的位置,並且可以根據子Widget的寬高來確定自身的寬高。
Align({
Key key,
this.alignment = Alignment.center,
this.widthFactor,
this.heightFactor,
Widget child,
})
- alignment:代表子Widget在父Widget的起始位置;
- widthFactor和heightFactor確定Align本身的寬高。
來看一個簡單的例子:
Container(
height: 120.0,
width: 120.0,
color: Colors.blue[50],
child: Align(
alignment: Alignment.topRight,
child: FlutterLogo(
size: 60,
),
),
)
運行結果:
3. 容器類組件
3.1 填充(Padding)
用過Android的同學一定熟悉,Padding就是負責留白的嘛。
但是跟Android裏面不同的是,在Android裏面我們一般是在一個View裏面添加Padding,但是在Flutter裏面,Padding直接變成了一個Widget、一個佈局。
使用方法:
Padding ({
EdgeInsetsGeometry padding,
Widget child,
})
對於EdgeInsetsGeometry我們一般使用EdgeInsets類。
EdgeInsets
EdgeInsets類提供了幾個便捷的方法:
- fromLTRB(double left, double top, double right, double bottom):分別指定四個方向的填充;
- all(double value) : 所有方向均使用相同數值的填充;
- only({left, top, right ,bottom }):可以設置具體某個方向的填充(可以同時指定多個方向);
- symmetric({ vertical, horizontal }):用於設置對稱方向的填充,vertical指top和bottom,horizontal指left和right;
示例:
body: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 12.0, bottom: 10.0),
child: Text("1234"),
),
Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 10.0),
child: Text("1234"),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: Text("1234"),
),
],
),
運行結果: