Flutter 组件 | Flex 弹性布局

1.Flex的属性一览

Flex 是 Column 和 Row 的父类,其中 Row 的 direction 是水平, Column是竖直。其他的属性都是类似的,相当于 Flex 的简化版。

属性名 类型 默认值 简介
direction Axis @required 轴向
mainAxisAlignment MainAxisAlignment start 主轴方向对齐方式
crossAxisAlignment CrossAxisAlignment center 交叉轴方向对齐方式
mainAxisSize MainAxisSize max 主轴尺寸
textDirection TextDirection null 文本方向
verticalDirection VerticalDirection down 竖直方向
textBaseline TextBaseline null 基线类型
children List

[]

内部孩子

2.轴向: direction

1enum Axis {
2  horizontal,//水平
3  vertical,//竖直
4}

也就是水平排放还是竖直排放,可以看出默认情况下都是主轴顶头,交叉轴居中

比如horizontal下主轴为水平轴,交叉轴则为竖直。也就是水平顶头,竖直居中

1var direction =[Axis.horizontal,Axis.vertical];
2var show = MultiShower(direction,(e){
3  return Flex(
4    direction: e,
5    children: [redBox,blueBox,yellowBox,greenBox],
6
7  );
8},color: Colors.black12,width: 300,height: 200);
9
10var redBox= Container(
11  color: Colors.red,
12  height: 50,
13  width: 50,
14);
15
16var blueBox= Container(
17  color: Colors.blue,
18  height: 30,
19  width: 60,
20);
21
22var yellowBox= Container(
23  color: Colors.yellow,
24  height: 50,
25  width: 100,
26);
27
28var greenBox= Container(
29  color: Colors.green,
30  height: 60,
31  width: 60,
32);

3.主轴方向: mainAxisAlignment

主轴方向的排布规则,这里以水平为例,主轴为水平方向。竖直类比即可

1enum MainAxisAlignment {
2  start,//顶头
3  end,//接尾
4  center,//居中
5  spaceBetween,//顶头接尾,其他均分
6  spaceAround,//中间的孩子均分,两头的孩子空一半
7  spaceEvenly,//均匀平分

1testMainAxisAlignment(){
2  var redBox= Container(
3    color: Colors.red,
4    height: 50,
5    width: 50,
6  );
7
8  var blueBox= Container(
9    color: Colors.blue,
10    height: 30,
11    width: 60,
12  );
13
14  var yellowBox= Container(
15    color: Colors.yellow,
16    height: 10,
17    width: 10,
18  );
19
20  var greenBox= Container(
21    color: Colors.green,
22    height: 50,
23    width: 10,
24  );
25
26  var mainAxisAlignment =[
27  MainAxisAlignment.start,MainAxisAlignment.center,
28  MainAxisAlignment.end,MainAxisAlignment.spaceAround,
29  MainAxisAlignment.spaceBetween,MainAxisAlignment.spaceEvenly];
30
31  var show = MultiShower(mainAxisAlignment,(e){
32    return Flex(
33      direction: Axis.horizontal,
34      mainAxisAlignment: e,
35      children: [redBox,blueBox,yellowBox,greenBox],
36
37    );
38  },color: Colors.black12,width: 200,height: 150);
39  return show;
40}

4.交叉轴方向: crossAxisAlignment

1enum CrossAxisAlignment {
2  start,//顶头
3  end,//接尾
4  center,//居中
5  stretch,//伸展
6  baseline,//基线
7}

还是水平为例,交叉轴便是竖轴,这里可以看出他们的布局行为

其中需要注意的是 CrossAxisAlignment.baseline 使用时必须有 textBaseline

其中textBaseline确定对齐的是那种基线,分为 alphabeticideographic

1testCrossAxisAlignment(){
2  var redBox= Container(
3    color: Colors.red,
4    height: 50,
5    width: 50,
6  );
7
8  var blueBox= Container(
9    color: Colors.blue,
10    height: 30,
11    width: 60,
12  );
13
14  var yellowBox= Container(
15    color: Colors.yellow,
16    height: 10,
17    width: 10,
18  );
19
20  var greenBox= Container(
21    color: Colors.green,
22    height: 50,
23    width: 10,
24  );
25
26  var crossAxisAlignment =[CrossAxisAlignment.start,CrossAxisAlignment.center,
27    CrossAxisAlignment.end,CrossAxisAlignment.stretch,CrossAxisAlignment.baseline];
28
29  var show = MultiShower(crossAxisAlignment,(e){
30    return Flex(
31      direction: Axis.horizontal,
32      crossAxisAlignment: e,
33      textBaseline: TextBaseline.alphabetic,//基线类型
34      children: [redBox,blueBox,yellowBox,greenBox],
35
36    );
37  },color: Colors.black12,width: 200,height: 140);
38
39  return show;
40}

5.主轴尺寸: mainAxisSize

1enum MainAxisSize {
2  min,
3  max,
4}

当父容器的宽未约束,Flex默认会将自身尽可能延伸,这便是MainAxisSize.max

此时改为MainAxisSize.min时,它不会延伸自己的区域,会包裹内容

1testMainAxisSize(){
2  var redBox= Container(
3    color: Colors.red,
4    height50,
5    width50,
6  );
7
8  var blueBox= Container(
9    color: Colors.blue,
10    height30,
11    width60,
12  );
13
14  var yellowBox= Container(
15    color: Colors.yellow,
16    height10,
17    width10,
18  );
19
20  var greenBox= Container(
21    color: Colors.green,
22    height50,
23    width10,
24  );
25
26  return Center(child: Flex(
27    direction: Axis.horizontal,
28    mainAxisSize: MainAxisSize.max,
29    children<Widget>[redBox,blueBox,yellowBox,greenBox],
30
31  ),);
32}
33

6.文字方向: textDirection

1enum TextDirection {
2  ltr,//从左到右
3  rtl,//从右到左
4}

这个非常好理解,不多言了

1testTextDirection(){
2  var redBox= Container(
3    color: Colors.red,
4    height: 50,
5    width: 50,
6  );
7
8  var blueBox= Container(
9    color: Colors.blue,
10    height: 30,
11    width: 60,
12  );
13
14  var yellowBox= Container(
15    color: Colors.yellow,
16    height: 10,
17    width: 10,
18  );
19
20  var greenBox= Container(
21    color: Colors.green,
22    height: 50,
23    width: 10,
24  );
25
26  var textDirection =[TextDirection.ltr,TextDirection.rtl];
27  var show = MultiShower(textDirection,(e){
28    return Flex(
29      direction: Axis.horizontal,
30      textDirection: e,
31      children: [redBox,blueBox,yellowBox,greenBox],
32
33    );
34  },color: Colors.black12,width: 200,height: 140);
35  return show;
36}

7.竖直方向排序: verticalDirection

1enum VerticalDirection{
2    up,
3    down,
4}

1testVerticalDirection(){
2  var redBox= Container(
3    color: Colors.red,
4    height: 50,
5    width: 50,
6  );
7
8  var blueBox= Container(
9    color: Colors.blue,
10    height: 30,
11    width: 60,
12  );
13
14  var yellowBox= Container(
15    color: Colors.yellow,
16    height: 10,
17    width: 10,
18  );
19
20  var greenBox= Container(
21    color: Colors.green,
22    height: 50,
23    width: 10,
24  );
25
26  var verticalDirection =[VerticalDirection.up,VerticalDirection.down];
27
28  var show = MultiShower(verticalDirection,(e){
29    return Flex(
30      direction: Axis.vertical,
31      verticalDirection: e
32      children: [redBox,blueBox,yellowBox,greenBox],
33
34    );
35  },color: Colors.black12,width: 200,height: 140);
36
37  return show;
38}

8.基线对齐方式: textBaseline

1enum TextBaseline {
2  alphabetic,
3  ideographic,
4}

1testTextBaseline(){
2  var redBox= Text(
3    "张风捷特烈",style: TextStyle(fontSize: 20,backgroundColor: Colors.red),
4  );
5
6  var blueBox= Text(
7    "toly",style: TextStyle(fontSize: 50,backgroundColor: Colors.blue),
8  );
9
10  var yellowBox=  Text(
11    "1994",style: TextStyle(fontSize: 30,backgroundColor: Colors.green),
12  );
13
14  var textBaseline =[TextBaseline.alphabetic,TextBaseline.ideographic];
15
16  var show = MultiShower(textBaseline,(e){
17    return Flex(
18      direction: Axis.horizontal,
19      crossAxisAlignment: CrossAxisAlignment.baseline,
20      textBaseline: e,
21      children: [redBox,blueBox,yellowBox],
22    );
23  },color: Colors.black12,width: 300,height: 140);
24
25  return show;
26}

9. Expanded与Flex的搭配

要一点是关于Expanded 组件,它能与 Flex 布局结合,对孩子组件区域进行延展。

1c1:绿色  c2:红色  c3:黄色
21).Expanded--c2:c1和c3将不变,c2延伸自己占满剩余部分
32).同时Expanded--c2和c3,最终c2和c3的长度是一样的
43).同时Expanded--c1,c2和c3,最终c1,c2,c3长度都是一样的

10.用Flex布局写个小例子

下面就用一个布局来实际看一下 Flex 的使用。

首先简单的分析一下

11.由上中下三行,可以用Column
22.第一行由图标,文字和文字组成,其中两头分处左右,可以用Expanded处理  
33.中间比较复杂由一个Row中包含两部分,左边是一个两行Column的内容,右边是文字  
44.底部是一个Row,主轴对齐是start

布局代码

1showItem() {
2  var infoStyle = TextStyle(color: Color(0xff999999), fontSize: 13);
3  var littleStyle = TextStyle(color: Colors.black, fontSize: 16);
4
5  var top = Row(//顶部,通过Flex布局的Row进行横向排列,Expanded中间
6    children: [
7      Image.asset("images/icon_head.png", width: 20, height: 20),
8      Expanded(
9        child: Padding(
10          child: Text("张风捷特烈"),
11          padding: EdgeInsets.only(left: 4),
12        ),
13      ),
14      Text(
15        "Flutter/Dart",
16        style: infoStyle,
17      )
18    ],
19  );
20
21  var content = Column(//中间文字内容,交叉轴为start
22    mainAxisSize: MainAxisSize.min,
23    crossAxisAlignment: CrossAxisAlignment.start,
24    children: [
25      Text(
26        "[Flutter必备]-Flex布局完全解读",
27        style: littleStyle,
28        maxLines: 2,
29        overflow: TextOverflow.ellipsis,
30      ),
31      Padding(
32        child: Text("也就是水平排放还是竖直排放,可以看出默认情况下都是主轴顶头,"
33            "交叉轴居中比如horizontal下主轴为水平轴,交叉轴则为竖直。也就是水平顶头,竖直居中"
34            "这里使用MultiShower快速展示,更好的对比出不同之处",
35            style: infoStyle, maxLines: 2, overflow: TextOverflow.ellipsis),
36        padding: EdgeInsets.only(top: 5),
37      ),
38    ],
39  );
40
41  var center = Row(//中间的部分
42    children: [
43      Expanded(
44          child: Padding(
45        child: content,
46        padding: EdgeInsets.all(5),
47      )),
48      ClipRRect(
49        borderRadius: BorderRadius.all(Radius.circular(5)),
50        child: Image.asset("images/wy_300x200.jpg",
51          width: 80, height: 80, fit: BoxFit.cover),)
52    ],
53  );
54
55  var end = Row(//底部
56    children: [
57      Icon(
58        Icons.grade,
59        color: Colors.green,
60        size: 20,
61      ),
62      Text(
63        "1000W",
64        style: infoStyle,
65      ),
66      Padding(child:Icon(Icons.tag_faces, color: Colors.lightBlueAccent, size: 20),
67          padding: EdgeInsets.symmetric(horizontal: 5),),
68      Text("2000W", style: infoStyle),
69    ],
70  );
71
72  var result = Card(//总体拼合
73      child: Container(
74          height: 160,
75          color: Colors.white,
76          padding: EdgeInsets.all(10),
77          child: Column(children: [top, Expanded(child: center), end])));
78  return result;
79}