老孟裏面控件非常全、可以去詳細學習
一、線性佈局Row 、Column
在Row和Column中有一個非常重要的概念:MainAxisAlignment(主軸)和CrossAxisAlignment(交叉軸),簡單來說,MainAxisAlignment(主軸)就是與當前控件方向一致的軸,而CrossAxisAlignment(交叉軸)就是與當前控件方向垂直的軸,比如Row的主軸是水平方向,交叉軸是垂直方向,而Column的主軸是垂直方向,交叉軸是水平方向。
Row和Column是多子控件的容器類控件,Row控件水平佈局,Column控件垂直佈局。
1、主軸對齊方式
Row控件的主軸mainAxisAlignment
對齊方式默認值是MainAxisAlignment.start
,即子控件從開始處排列,這個開始處不一定是屏幕的左邊,是從左到右還是從右到左排列取決於文本方向textDirection
屬性,比如阿拉伯文本方向是從右到左的。
Row(
children: <Widget>[
Container(
height: 50,
width: 100,
color: Colors.red,
),
Container(
height: 50,
width: 100,
color: Colors.green,
),
Container(
height: 50,
width: 100,
color: Colors.blue,
),
],
)
效果如圖:
黑色邊框是Row控件的範圍,默認情況下Row鋪滿父組件。主軸的對齊方式設置代碼如下:
Row(
mainAxisAlignment: MainAxisAlignment.center,
...
)
主軸對齊方式有6種,效果如下圖:
spaceAround和spaceEvenly區別是:
- spaceAround:第一個子控件距開始位置和最後一個子控件距結尾位置是其他子控件間距的一半。
- spaceEvenly:所有間距一樣。
2、交叉軸對齊方式
和主軸相對應的就是交叉軸crossAxisAlignment
,交叉軸對齊方式默認是居中。Row控件的高度是依賴子控件高度,因此子控件高都一樣時,Row的高和子控件高相同,此時是無法體現交叉軸對齊方式,修改3個顏色塊高分別爲50,100,150,這樣Row的高是150,代碼如下:
Row(
children: <Widget>[
Container(
height: 50,
width: 100,
color: Colors.red,
),
Container(
height: 100,
width: 100,
color: Colors.green,
),
Container(
height: 150,
width: 100,
color: Colors.blue,
),
],
)
效果如下:
交叉軸屬性設置代碼如下:
Row(
crossAxisAlignment: CrossAxisAlignment.center,
...
)
交叉軸對齊方式介紹如下:
CrossAxisAlignment.stretch
表示使子控件填滿交叉軸。
3、主軸尺寸
主軸尺寸由mainAxisSize
屬性控制,僅有min
和max
兩種方式,默認是max
方法。min
表示儘可能小,而max
表示儘可能大,設置min
的代碼如下:
Row(
mainAxisSize: MainAxisSize.min,
...
)
效果如下:
黑色邊框是Row的邊框。
二、Flex佈局
Flex
組件可以沿着水平或垂直方向排列子組件,如果你知道主軸方向,使用Row
或Column
會方便一些,因爲Row
和Column
都繼承自Flex
,參數基本相同,所以能使用Flex的地方基本上都可以使用Row
或Column
。Flex
本身功能是很強大的,它也可以和Expanded
組件配合實現彈性佈局。接下來我們只討論Flex
和彈性佈局相關的屬性(其它屬性已經在介紹Row
和Column
時介紹過了)。
Flex({
@required this.direction, //彈性佈局的方向, Row默認爲水平方向,Column默認爲垂直方向
//direction: Axis.horizontal,
List<Widget> children = const <Widget>[],
})
Expanded、Flexible和Spacer都是具有權重屬性的組件,可以控制Row、Column、Flex的子控件如何佈局的控件。
Row(
children: <Widget>[
Container(
color: Colors.blue,
height: 50,
width: 100,
),
Flexible(
child: Container(
color: Colors.red,
height: 50,
)
),
Container(
color: Colors.blue,
height: 50,
width: 100,
),
],
)
效果如圖:
還是有3個子控件,希望第一個佔1/6,第二個佔2/6,第三個佔3/6,代碼如下:
Column(
children: <Widget>[
Flexible(
flex: 1,
child: Container(
color: Colors.blue,
alignment: Alignment.center,
child: Text('1 Flex/ 6 Total',style: TextStyle(color: Colors.white),),
),
),
Flexible(
flex: 2,
child: Container(
color: Colors.red,
alignment: Alignment.center,
child: Text('2 Flex/ 6 Total',style: TextStyle(color: Colors.white),),
),
),
Flexible(
flex: 3,
child: Container(
color: Colors.green,
alignment: Alignment.center,
child: Text('3 Flex/ 6 Total',style: TextStyle(color: Colors.white),),
),
),
],
)
效果如圖:
Spacer的通過Expanded的實現的,和Expanded的區別是:Expanded可以設置子控件,而Spacer的子控件尺寸是0,因此Spacer適用於撐開Row、Column、Flex的子控件的空隙,用法如下:
Row(
children: <Widget>[
Container(width: 100,height: 50,color: Colors.green,),
Spacer(flex: 2,),
Container(width: 100,height: 50,color: Colors.blue,),
Spacer(),
Container(width: 100,height: 50,color: Colors.red,),
],
)
效果如下:
總結如下:
- Spacer是通過Expanded來實現的,Expanded繼承自Flexible。
- 填滿剩餘空間直接使用Expanded更方便。
- Spacer用於撐開Row、Column、Flex的子控件的空隙。
三、Stack、Positioned
Stack 這個是Flutter中佈局用到的組件,跟Android中FrameLayout很像,都是可以疊加的現實View,具體的使用細節還是有些不同的,我們一一說來
Stack({
Key key,
this.alignment = AlignmentDirectional.topStart,
this.textDirection,
this.fit = StackFit.loose,
this.overflow = Overflow.clip,
List<Widget> children = const <Widget>[],
})
-
alignment : 指的是子Widget的對其方式,默認情況是以左上角爲開始點 ,這個屬性是最難理解的,它區分爲使用了Positioned和未使用Positioned定義兩種情況,沒有使用Positioned情況還是比較好理解的,下面會詳細講解的
-
fit :用來決定沒有Positioned方式時候子Widget的大小,StackFit.loose 指的是子Widget 多大就多大,StackFit.expand使子Widget的大小和父組件一樣大
-
overflow :指子Widget 超出Stack時候如何顯示,默認值是Overflow.clip,子Widget超出Stack會被截斷,
Overflow.visible超出部分還會顯示的
這些會是挺好懂的 主要介紹一下
Positioned
Positioned({
Key key,
this.left,
this.top,
this.right,
this.bottom,
this.width,
this.height,
@required Widget child,
})
left、top 、right、 bottom分別代表離Stack左、上、右、底四邊的距離
class PositionScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Postion Title"),
),
body: Stack(
children: <Widget>[
Positioned(
left: 0,
top: 0,
right: 0,
bottom: 0,
child: Container(
color: Colors.black45,
),
),
Positioned(
top: 100.0,
left: 0,
right: 0,
child: Container(
color: Colors.blue,
child: Text("第一個組件"),
),
),
Positioned(
top: 200,
right: 100,
child: Container(
color: Colors.yellow,
child: Text("第二個組件"),
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
color: Colors.red,
child: Text("第三個組件"),
),
),
],
),
);
}
}
那麼我們如果指定了left&&right&&top&bottom都是0的情況
那麼這個組件就是和Stack大小一樣填滿它
IndexedStack
IndexedStack是Stack的子類,Stack是將所有的子組件疊加顯示,而IndexedStack只顯示指定的子組件,用法如下:
IndexedStack(
index: _index,
children: <Widget>[
Center(
child: Container(
height: 300,
width: 300,
color: Colors.red,
alignment: Alignment.center,
child: Icon(
Icons.fastfood,
size: 60,
color: Colors.blue,
),
),
),
Center(
child: Container(
height: 300,
width: 300,
color: Colors.green,
alignment: Alignment.center,
child: Icon(
Icons.cake,
size: 60,
color: Colors.blue,
),
),
),
Center(
child: Container(
height: 300,
width: 300,
color: Colors.yellow,
alignment: Alignment.center,
child: Icon(
Icons.local_cafe,
size: 60,
color: Colors.blue,
),
),
),
],
)
通過點擊按鈕更新_index
值,代碼如下:
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
icon: Icon(Icons.fastfood),
onPressed: () {
setState(() {
_index = 0;
});
},
),
IconButton(
icon: Icon(Icons.cake),
onPressed: () {
setState(() {
_index = 1;
});
},
),
IconButton(
icon: Icon(Icons.local_cafe),
onPressed: () {
setState(() {
_index = 2;
});
},
),
],
)
效果如下: