线性、弹性、流式和层叠布局,Flutter中

  Flutter中通过Row和Column来实现线性布局,类似于Android中的LinearLayout控件。Row和Column都继承自Flex,弹性布局Flex允许子组件按照一定比例来分配父容器空间。超出屏幕显示范围会自动折行的布局称为流式布局。Flutter中通过Wrap和Flow来支持流式布局。层叠布局和Android中的Frame布局是相似的,子组件可以根据距父容器四个角的位置来确定自身的位置。绝对定位允许子组件堆叠起来(按照代码中声明的顺序)。Flutter中使用Stack和Positioned这两个组件来配合实现绝对定位。Stack允许子组件堆叠,而Positioned用于根据Stack的四个角来确定子组件的位置。
  一、线性布局
  1.1主轴和交叉轴
  对于线性布局,有主轴和交叉轴之分,如果布局是沿水平方向,那么主轴就是指水平方向,而交叉轴即垂直方向;如果布局沿垂直方向,那么主轴就是指垂直方向,而交叉轴就是水平方向。在线性布局中,有两个定义对齐方式的枚举类MainAxisAlignment和CrossAxisAlignment,分别代表主轴对齐和交叉轴对齐。
  主轴对齐----MainAxisAlignment
  交叉轴对齐----CrossAxisAlignment
  下面是MainAxisAlignment,它也是一个枚举类。

enum MainAxisAlignment {
  start,
  end,
  center,
  spaceBetween,
  spaceAround,
  spaceEvenly,
}

  start----将子Widget放置在尽可能靠近主轴起点的位置。如果在水平方向上使用此值,则[TextDirection]必须可用以确定起点是左侧还是右侧;如果在垂直方向上使用此值,则[VerticalDirection]必须可用以确定起点是顶部还是底部。
  end----将子Widget放置在尽可能靠近主轴末端的位置。如果在水平方向上使用此值,则[TextDirection]必须可用以确定结尾是左侧还是右侧;如果在垂直方向上使用此值,则必须使用[VerticalDirection]来确定末端是顶部还是底部。
  center----将子Widget放置在尽可能靠近主轴中心的位置。
  spaceBetween----将空闲空间均匀地放在子Widget之间。
  spaceAround----在子Widget之间以及第一个和最后一个子Widget之前和之后的一半空间之间均匀地放置可用空间。这段文字有点绕,接下来看实例就非常清晰了。
  spaceEvenly----将空闲空间均匀地放在子Widget之间以及第一个和最后一个子Widget子之前和之后。
  下面是CrossAxisAlignment,它也是一个枚举类。

enum CrossAxisAlignment {
  start,
  end,
  center,
  stretch,
  baseline,
}

  start----将子项的起始边缘与交叉轴的起始侧对齐。如果在水平方向上使用此值,则[TextDirection]必须可用以确定起点是左侧还是右侧;如果在垂直方向上使用此值,则[VerticalDirection]必须可用以确定起点是顶部还是底部。
  end----将子Widget放置在尽可能靠近交叉轴末端的位置。如果在水平方向上使用此值,则[TextDirection]必须可用以确定结尾是左侧还是右侧;如果在垂直方向上使用此值,则必须使用[VerticalDirection]来确定末端是顶部还是底部。
  center----放置子Widget使其中心与交叉轴的中心对齐。这是默认的横轴对齐方式。
  stretch----要求子Widget填满交叉轴。
  baseline----沿交叉轴放置子Widget,使其基线匹配。如果主轴是垂直的,则将此值视为[start](因为基线始终是水平的)。

Row({
    Key key,
    MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
    MainAxisSize mainAxisSize = MainAxisSize.max,
    CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
    TextDirection textDirection,
    VerticalDirection verticalDirection = VerticalDirection.down,
    TextBaseline textBaseline,
    List<Widget> children = const <Widget>[],
  })

  mainAxisAlignment----表示子组件在Row所占用的水平空间内对齐方式,如果mainAxisSize值为MainAxisSize.min,则此属性无意义,因为子组件的宽度等于Row的宽度。只有当mainAxisSize的值为MainAxisSize.max时,此属性才有意义。
  textDirection----表示水平方向子组件的布局顺序(是从左往右还是从右往左),默认为系统当前Locale环境的文本方向(如中文、英语都是从左往右,而阿拉伯语是从右往左)。
  mainAxisSize----表示Row在主轴(水平)方向占用的空间,默认是MainAxisSize.max,表示尽可能多的占用水平方向的空间,此时无论子widgets实际占用多少水平空间,Row的宽度始终等于水平方向的最大宽度;而MainAxisSize.min表示尽可能少的占用水平空间,当子组件没有占满水平剩余空间,则Row的实际宽度等于所有子组件占用的的水平空间。
  verticalDirection----表示Row垂直的对齐方向,默认是VerticalDirection.down,表示从上到下。
  crossAxisAlignment----表示子组件在纵轴方向的对齐方式,Row的高度等于子组件中最高的子元素高度。
  children----子组件数组。
  textBaseline----用于对齐文本的水平线。
  TextBaseline是一个枚举类,它包括alphabetic和ideographic。

  Column({
  Key key,
  MainAxisAlignment mainAxisAlignment=MainAxisAlignment.start,
  MainAxisSize mainAxisSize=MainAxisSize.max,
  CrossAxisAlignment crossAxisAlignment=CrossAxisAlignment.center,
  TextDirection textDirection,
  VerticalDirection verticalDirection=VerticalDirection.down,
  TextBaseline textBaseline,
  List&lt;Widget&gt;children=const&lt;Widget&gt;[],
  })
  1
  2
  3
  4
  5
  6
  7
  8
  9
  10
  下面来看一个例子。
  import'package:flutter/material.dart';
  void main()=&gt;runApp(MyApp());
  class MyApp extends StatelessWidget{
  //This widget is the root of your application.
   override
  Widget build(BuildContext context){
  return MaterialApp(
  title:'Flutter Demo',
  theme:ThemeData(
  primarySwatch:Colors.blue,
  ),
  home:MyHomePage(),
  );
  }
  }
  class MyHomePage extends StatefulWidget{
   override
  _MyHomePageState createState()=&gt;_MyHomePageState();
  }
  class _MyHomePageState extends State&lt;MyHomePage&gt;{
   override
  Widget build(BuildContext context){
  return Scaffold(
  appBar:AppBar(
  title:Text("Home Page"),
  ),
  body:Column(mainAxisAlignment:MainAxisAlignment.start,children:&lt;
  Widget&gt;[
  Row(mainAxisAlignment:MainAxisAlignment.start,children:&lt;Widget&gt;[
  Text(
  'Test1',
  ),
  Text(
  'Test2',
  ),
  Text(
  'Test3',
  ),
  Text(
  'Test4',
  )
  ]),
  Row(mainAxisAlignment:MainAxisAlignment.end,children:&lt;Widget&gt;[
  Text(
  'Test1',
  ),
  Text(
  'Test2',
  ),
  Text(
  'Test3',
  ),
  Text(
  'Test4',
  )
  ]),
  Row(mainAxisAlignment:MainAxisAlignment.center,children:&lt;Widget&gt;[
  Text(
  'Test1',
  ),
  Text(
  'Test2',
  ),
  Text(
  'Test3',
  ),
  Text(
  'Test4',
  )
  ]),
  Row(
  mainAxisAlignment:MainAxisAlignment.spaceBetween,
  children:&lt;Widget&gt;[
  Text(
  'Test1',
  ),
  Text(
  'Test2',
  ),
  Text(
  'Test3',
  ),
  Text(
  'Test4',
  )
  ]),
  Row(
  mainAxisAlignment:MainAxisAlignment.spaceAround,
  children:&lt;Widget&gt;[
  Text(
  'Test1',
  ),
  Text(
  'Test2',
  ),
  Text(
  'Test3',
  ),
  Text(
  'Test4',
  )
  ]),
  Row(
  mainAxisAlignment:MainAxisAlignment.spaceEvenly,
  children:&lt;Widget&gt;[
  Text(
  'Test1',
  ),
  Text(
  'Test2',
  ),
  Text(
  'Test3',
  ),
  Text(
  'Test4',
  )
  ]),
  ]));
  }
  }
  1
  2
  3
  4
  5
  6
  7
  8
  9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  下面是对应的截图,对于Row行布局MainAxisAlignment理解就会一目了然。
  接下来修改Demo,看看交叉轴控制。
  class _MyHomePageState extends State&lt;MyHomePage&gt;{
   override
  Widget build(BuildContext context){
  return Scaffold(
  appBar:AppBar(
  title:Text("Home Page"),
  ),
  body:Column(
  mainAxisAlignment:MainAxisAlignment.start,
  children:&lt;Widget&gt;[
  Row(
  mainAxisAlignment:MainAxisAlignment.start,
  crossAxisAlignment:CrossAxisAlignment.center,
  children:&lt;Widget&gt;[
  Text(
  'Test1',
  textScaleFactor:3.0,
  ),
  Text(
  'Test2',
  ),
  Text(
  'Test3',
  ),
  Text(
  'Test4',
  )
  ]),
  Row(
  mainAxisAlignment:MainAxisAlignment.start,
  crossAxisAlignment:CrossAxisAlignment.start,
  children:&lt;Widget&gt;[
  Text(
  'Test1',
  textScaleFactor:3.0,
  ),
  Text(
  'Test2',
  ),
  Text(
  'Test3',
  ),
  Text(
  'Test4',
  )
  ]),
  Row(
  mainAxisAlignment:MainAxisAlignment.start,
  crossAxisAlignment:CrossAxisAlignment.end,
  children:&lt;Widget&gt;[
  Text(
  'Test1',
  textScaleFactor:3.0,
  ),
  Text(
  'Test2',
  ),
  Text(
  'Test3',
  ),
  Text(
  'Test4',
  )
  ]),
  ]));
  }
  }
  1
  2
  3
  4
  5
  6
  7
  8
  9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  再来研究一下交叉轴crossAxisAlignment设置为CrossAxisAlignment.stretch的效果,它要求子Widget填满交叉轴。对于Row来说交叉轴就是垂直方向。
  class _MyHomePageState extends State&lt;MyHomePage&gt;{
   override
  Widget build(BuildContext context){
  return Scaffold(
  appBar:AppBar(
  title:Text("Home Page"),
  ),
  body:Row(
  mainAxisAlignment:MainAxisAlignment.start,
  crossAxisAlignment:CrossAxisAlignment.stretch,
  children:&lt;Widget&gt;[
  Text(
  'Test1',
  textScaleFactor:3.0,
  ),
  Text(
  'Test2',
  ),
  Text(
  'Test3',
  ),
  Text(
  'Test4',
  )
  ]));
  }
  }
  1
  2
  3
  4
  5
  6
  7
  8
  9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  二、弹性布局
  我们先来看一下Flex如何使用,接着来看搭配Expanded组件使用方法。
  2.1 Flex
  Flex组件可以沿着水平或垂直方向排列子组件,如果你知道主轴方向,使用Row或Column会方便一些,因为Row和Column都继承自Flex,参数基本相同,所以能使用Flex的地方基本上都可以使用Row或Column。Flex本身功能是很强大的,它也可以和Expanded组件配合实现弹性布局。
  Flex({
  Key key,
   required this.direction,
  this.mainAxisAlignment=MainAxisAlignment.start,
  this.mainAxisSize=MainAxisSize.max,
  this.crossAxisAlignment=CrossAxisAlignment.center,
  this.textDirection,
  this.verticalDirection=VerticalDirection.down,
  this.textBaseline,
  List&lt;Widget&gt;children=const&lt;Widget&gt;[],
  })
  1
  2
  3
  4
  5
  6
  7
  8
  9
  10
  11
  和Row、Column比起来多了一个direction,它是弹性布局的方向,Row默认为水平方向,Column默认为垂直方向。修改上面的例子把Row和Column替换为Flex,可以看出效果的确是一样的。
  class _MyHomePageState extends State&lt;MyHomePage&gt;{
   override
  Widget build(BuildContext context){
  return Scaffold(
  appBar:AppBar(
  title:Text("Home Page"),
  ),
  body:Flex(
  mainAxisAlignment:MainAxisAlignment.start,
  direction:Axis.vertical,
  children:&lt;Widget&gt;[
  Flex(
  mainAxisAlignment:MainAxisAlignment.start,
  direction:Axis.horizontal,
  children:&lt;Widget&gt;[
  Text(
  'Test1',
  ),
  Text(
  'Test2',
  ),
  Text(
  'Test3',
  ),
  Text(
  'Test4',
  )
  ]),
  Flex(
  mainAxisAlignment:MainAxisAlignment.end,
  direction:Axis.horizontal,
  children:&lt;Widget&gt;[
  Text(
  'Test1',
  ),
  Text(
  'Test2',
  ),
  Text(
  'Test3',
  ),
  Text(
  'Test4',
  )
  ]),
  ]));
  }
  }
  1
  2

  44
  45
  46
  47
  48
  49
  来看上面代码的运行结果:
  2.2 Expanded
  可以按比例“扩伸”Row、Column和Flex子组件所占用的空间。这和android里面控件的weight类似。
  const Expanded({
  Key key,
  int flex=1,
   required Widget child,
  })
  1
  2
  3
  4
  5
  flex----为弹性系数,如果为0或null,则child是没有弹性的,即不会被扩伸占用的空间。如果大于0,所有的Expanded按照其flex的比例来分割主轴的全部可用空间。
  class _MyHomePageState extends State&lt;MyHomePage&gt;{
   override
  Widget build(BuildContext context){
  return Scaffold(
  appBar:AppBar(
  title:Text("Home Page"),
  ),
  body:Flex(
  mainAxisAlignment:MainAxisAlignment.start,
  direction:Axis.vertical,
  children:&lt;Widget&gt;[
  Expanded(
  flex:2,
  child:Flex(
  mainAxisAlignment:MainAxisAlignment.start,
  direction:Axis.horizontal,
  children:&lt;Widget&gt;[
  Text(
  'Test1',
  ),
  Text(
  'Test2',
  ),
  Text(
  'Test3',
  ),
  Text(
  'Test4',
  )
  ]),
  ),
  Expanded(
  flex:2,
  child:Flex(
  mainAxisAlignment:MainAxisAlignment.end,
  direction:Axis.horizontal,
  children:&lt;Widget&gt;[
  Text(
  'Test1',
  ),
  Text(
  'Test2',
  ),
  Text(
  'Test3',
  ),
  Text(
  'Test4',
  )
  ]),
  )
  ]));
  }
  }

猜你喜欢

转载自www.cnblogs.com/525jik/p/12702713.html