1、Flex
弹性布局允许子组件按照必定比例来分配父容器空间
Flex组件和Row、Column属性主要的区别就是多一个direction。
当direction的值为Axis.horizontal的时候,则是Row。
当direction的值为Axis.vertical的时候,则是Column。
它们之中都有主轴(MainAxis)和交叉轴(CrossAxis)的概念:
-
对于Row来说,主轴(MainAxis)和交叉轴(CrossAxis)分别是下图

-
对于Column来说,主轴(MainAxis)和交叉轴(CrossAxis)分别是下图

2. Row
Row可以沿水平方向排列其子widget。定义如下:
Row({
Key? key,
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
MainAxisSize mainAxisSize = MainAxisSize.max,
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
TextDirection? textDirection,
VerticalDirection verticalDirection = VerticalDirection.down,
TextBaseline? textBaseline, // NO DEFAULT: we don t know what the text s baseline should be
List<Widget> children = const <Widget>[],
}
-
textDirection:表明水平方向子组件的布局顺序(是从左往右还是从右往左),默认为系统当前Locale环境的文本方向(如中文、英语都是从左往右,而阿拉伯语是从右往左)。对于Row,它决定的是主轴的布局顺序,对于‘Column’ ,它决定的是交叉轴的布局顺序 -
mainAxisSize:表明Row在主轴(水平)方向占用的空间,默认是MainAxisSize.max,表明尽可能多的占用水平方向的空间,此时无论子 widgets 实际占用多少水平空间,Row的宽度始终等于水平方向的最大宽度;而MainAxisSize.min表明尽可能少的占用水平空间,当子组件没有占满水平剩余空间,则Row的实际宽度等于所有子组件占用的的水平空间; -
mainAxisAlignment:表明子组件在Row所占用的水平空间内对齐方式,如果mainAxisSize值为MainAxisSize.min,则此属性无意义,由于子组件的宽度等于Row的宽度。只有当mainAxisSize的值为MainAxisSize.max时,此属性才有意义,MainAxisAlignment.start表明沿textDirection的初始方向对齐,如textDirection取值为TextDirection.ltr时,则MainAxisAlignment.start表明左对齐,textDirection取值为TextDirection.rtl时表明从右对齐。而MainAxisAlignment.end和MainAxisAlignment.start正好相反;MainAxisAlignment.center表明居中对齐。读者可以这么理解:textDirection是mainAxisAlignment的参考系。 -
verticalDirection:表明Row纵轴(垂直)的对齐方向,默认是VerticalDirection.down,表明从上到下。对于Row,它决定的是交叉轴的布局顺序,对于‘Column’ ,它决定的是主轴的布局顺序 -
crossAxisAlignment:表明子组件在纵轴方向的对齐方式,Row的高度等于子组件中最高的子元素高度,它的取值和MainAxisAlignment一样(包含start、end、center三个值),不同的是crossAxisAlignment的参考系是verticalDirection,即verticalDirection值为VerticalDirection.down时crossAxisAlignment.start指顶部对齐,verticalDirection值为VerticalDirection.up时,crossAxisAlignment.start指底部对齐;而crossAxisAlignment.end和crossAxisAlignment.start正好相反; -
children:子组件数组。
2.1 案例
示例1 – 基本使用
/**
* Row特点
* - 水平方向尽可能占据比较大的空间
* * 水平方向也希望包裹内容,那么设置mainAxisSize = min
* - 垂直方向包裹内容
* mainAxisAlignment:
* - start: 主轴的开始位置挨个摆放元素(默认)
* - end: 主轴的结束位置挨个摆放元素
* - center: 主轴的中心点对齐
* - spaceBetween:左右两边的间距为0,其他元素之间平分间距
* - spaceAround: 左右两边的间距是其他元素之间间距的一半
* - spaceEvenly: 所有的间距平分空间
*
* CrossAxisAlignment:
* - start:交叉轴的起始位置对齐
* - end: 交叉轴的结束位置对齐
* - center:交叉轴的中心点对齐 (默认)
* - stretch:先Row占据交叉轴尽可能大的空间,将所有的子Widget交叉轴的高度,拉伸到最大
* - baseline:基线对齐(必须有文本的时候才起作用) 要设置textBaseline 类型
*
*/
class RowDemo1 extends StatelessWidget {
const RowDemo1({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.end,
verticalDirection: VerticalDirection.down,
children: [
Container(width: 80, height: 60, color: Colors.red),
Container(width: 100, height: 100, color: Colors.blue),
Container(width: 90, height: 60, color: Colors.orange),
Container(width: 50, height: 120, color: Colors.purple),
],
);
}
}

示例2 – 基线对齐
基线是英文字母X的下端两点连成的一条线
class RowDemo2 extends StatelessWidget {
const RowDemo2({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Container(
width: 80,
height: 60,
color: Colors.red,
child: Text("ABX", style: TextStyle(fontSize: 25))),
Container(
width: 100,
height: 100,
color: Colors.blue,
child: Text("ABX", style: TextStyle(fontSize: 20))),
Container(
width: 90,
height: 60,
color: Colors.orange,
child: Text("ABX", style: TextStyle(fontSize: 10))),
Container(
width: 50,
height: 120,
color: Colors.purple,
child: Text("ABX", style: TextStyle(fontSize: 18))),
],
);
}
}

示例3 – 水平方向包裹
class RowDemo3 extends StatelessWidget {
const RowDemo3({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {},
child: Row(
// 主轴方向 包裹内容
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.people),
Text("UserName"),
],
),
);
}
}

3. Column
Column可以沿垂直方向排列其子widget。定义如下:
Column({
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>[],
})
3.1 示例
Column 基本使用 示例
class ColumnDemo1 extends StatelessWidget {
const ColumnDemo1({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
textDirection: TextDirection.ltr, // 水平方向 显示方向 默认 ltr
crossAxisAlignment: CrossAxisAlignment.end,
verticalDirection: VerticalDirection.up, // 垂直方向 显示方向 默认down
children: [
Container(width: 80, height: 60, color: Colors.red),
Container(width: 100, height: 100, color: Colors.blue),
Container(width: 90, height: 60, color: Colors.orange),
Container(width: 50, height: 120, color: Colors.purple),
],
);
}
}

再看一个示例
class _MSHomeContentState extends State<MSHomeContent> {
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("Hello World"),
Text("Hi"),
],
);
}
}
运行效果如下:

我们发现文本并没有居中?
解释:
- 由于我们没有指定Column的mainAxisSize,所以使用默认值MainAxisSize.max,则Column会在垂直方向占用尽可能多的空间,此例中会占满整个屏幕高度。
- 由于我们指定了 crossAxisAlignment 属性为CrossAxisAlignment.center,那么子项在Column纵轴方向(此时为水平方向)会居中对齐。注意,在水平方向对齐是有边界的,总宽度为Column占用空间的实际宽度,而实际的宽度取决于子项中宽度最大的Widget。在本例中,Column有两个子Widget,而显示“world”的Text宽度最大,所以Column的实际宽度则为Text(“world”) 的宽度,所以居中对齐后Text(“hi”)会显示在Text(“world”)的中间部分。
实际上,Row和Column都只会在主轴方向占用尽可能大的空间,而交叉轴的长度则取决于他们最大子元素的长度。如果我们想让本例中的两个文本控件在整个手机屏幕中间对齐,我们有两种方法:
- 将Column的宽度指定为屏幕宽度;这很简单,我们可以通过ConstrainedBox、SizedBox、Container
class ColumnDemo2 extends StatelessWidget {
const ColumnDemo2({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints(minWidth: double.infinity),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("Hello World"),
Text("Hi"),
],
),
);
}
}
- 使用Center组件对齐
class ColumnDemo3 extends StatelessWidget {
const ColumnDemo3({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("Hello World"),
Text("Hi"),
],
),
);
}
}
运行效果如下:

4. Row Column 嵌套
如果Row里面嵌套Row,或者Column里面再嵌套Column,那么只有最外面的Row或Column会占用尽可能大的空间,里面Row或Column所占用的空间为实际大小,下面以Column为例说明
class ColumnDemo4 extends StatelessWidget {
const ColumnDemo4({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
padding: EdgeInsets.all(8),
child: Column(
mainAxisSize: MainAxisSize.max, // //有效,外层Colum高度为整个屏幕
children: [
Container(
color: Colors.red,
child: Column(
mainAxisSize: MainAxisSize.max, // //无效,内层Colum高度为实际高度
children: [
Text("Hello World"),
Text("Hi"),
],
),
)
],
),
);
}
}

如果要让里面的Column占满外部Column,可以使用Expanded 组件:
class ColumnDemo5 extends StatelessWidget {
const ColumnDemo5({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
padding: EdgeInsets.all(8),
child: Column(
mainAxisSize: MainAxisSize.max, // //有效,外层Colum高度为整个屏幕
children: [
Expanded(
child: Container(
color: Colors.red,
child: Column(
mainAxisSize: MainAxisSize.max, // //无效,内层Colum高度为实际高度
children: [
Text("Hello World"),
Text("Hi"),
],
),
),
)
],
),
);
}
}


















暂无评论内容