前言
做Android开发的朋友知道,在进行Android开始时,我们常用到的布局有
- LinearLayout(线性布局)
- RelativeLayout(相对布局)
- FrameLayout(帧布局)
- AbsoluteLayout(绝对布局)
- TableLayout(表格布局)
- ConstraintLayout(约束布局)
接下来我们看下在Flutter中的布局又有哪些来供给我们使用
正文 - 布局的分类
按照子Widget的数量进行分类:
- 单子Widget布局:布局Widget中只能包含一个子Widget的
如:
Center(
child: Text("data")
)
Center就是单子Widget的布局,它的子Widget属性是child,而且只能有一个
- 多子Widget布局:布局Widget中可以含有多个子Widget的
如:
Column(
children: [
Text("data"),
Text("data")
...
],
)
Column就是多子Widget的布局,它的子Widget属性是children,是Widget数组,可以有多个Widget
布局Widget还可以按照子元素排布的方式进行分类:
- 弹性布局 - Flex
先看下效果图
下面看下Flex的使用方法
Flex(
direction: Axis.vertical,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: _getWidgets(),
)
对应的就是效果图中的第一个排列效果
在了解Flex的构造函数前,我们需要了解在Flex的使用过程中的另外两个概念,主轴和交叉轴
看下图
由图可见,通俗的说其实就是水平方向和垂直方向的轴线
当主轴是水平方向,交叉轴就是垂直方向
当主轴是垂直方向,交叉轴就是水平方向
了解了上图后我们下面要介绍的参数概念就好理解了
接下来我们看下Flex的构造函数
Flex({
Key key,
@required this.direction,//主轴的方向,类型Axis
this.mainAxisAlignment = MainAxisAlignment.start,//子Widget在主轴的对齐方式,类型MainAxisAlignment
this.mainAxisSize = MainAxisSize.max,//主轴应该占用多大的空间,类型MainAxisSize
this.crossAxisAlignment = CrossAxisAlignment.center,//子Widget在交叉轴的对齐方式,类型CrossAxisAlignment
this.textDirection,//子Widget在主轴方向上的布局顺序,类型TextDirection
this.verticalDirection = VerticalDirection.down,//子Widget 在交叉轴方向上的布局顺序,类型VerticalDirection
this.textBaseline,//排列子Widget时使用哪个基线,类型TextBaseline
List children = const [],//Flex布局里面排列的内容
}) : assert(direction != null),
...;
PS: 这里需要注意 direction参数是必传参数,当crossAxisAlignment为CrossAxisAlignment.baseline的时候,textBaseline也不能为空
Axis(主轴的方向)- 2种方式
- Axis.horizontal:主轴方向为水平方向,那么 子Widget 就会沿水平方向排列,交叉轴就是垂直方向
- Axis.vertical:主轴方向为垂直方向,那么 子Widget 就会沿垂直方向排列,交叉轴就是水平方向
MainAxisAlignment(子Widget 在主轴的对齐方式) -6种方式
- MainAxisAlignment.start:沿着主轴的起点对齐
textDirection 必须有值,以确定是从左边开始的还是从右边开始的 - MainAxisAlignment.end:沿着主轴的终点对齐
textDirection 必须有值,以确定是在左边结束的还是在右边结束的 - MainAxisAlignment.center:在主轴上居中对齐
- MainAxisAlignment.spaceBetween:在主轴上,两端对齐,项目之间的间隔都相等。
- MainAxisAlignment.spaceAround:在主轴上,将多余的控件均匀分布给 子Widget 之间,而且第一个 子Widget 和 最后一个子Widget 距边框的距离是 两个 子Widget 距离的一半
- MainAxisAlignment.spaceEvenly:在主轴上,将多余的控件均匀分布给 子Widget 之间,而且第一个 子Widget 和 最后一个子Widget 距边框的距离和 子Widget 之间的距离一样
MainAxisSize( 表示主轴应该占用多大的空间)- 2种方式
- MainAxisSize.min:主轴的大小是能显示完 子Widget 的最小大小,主轴的大小就是 子Widget 的大小
- MainAxisSize.max:主轴能显示的最大的大小,根据约束来判断
CrossAxisAlignment(表示 子Widget 在交叉轴的对齐方式)-5种方式
- CrossAxisAlignment.start:沿着交叉轴的起点对齐
verticalDirection 必须有值,以确定是从左边开始的还是从右边开始的 - CrossAxisAlignment.end:沿着主轴的终点对齐
verticalDirection 必须有值,以确定是在左边结束的还是在右边结束的 - CrossAxisAlignment.center:在交叉轴上居中对齐
- CrossAxisAlignment.stretch:要求 子Widget 在交叉轴上填满
- CrossAxisAlignment.baseline:要求 子Widget 的基线在交叉轴上对齐
TextDirection:(子Widget 在主轴方向上的布局顺序)-2种方式
- TextDirection.rtl:表示从右到左
- TextDirection.ltr:表示从左到右
VerticalDirection:(子Widget 在交叉轴方向上的布局顺序)-2种方式
- VerticalDirection.up:表示从下到上
- VerticalDirection.down:表示从上到下
此处为分割线,到此为止Flex的介绍就结束了
- 线性布局 - Row(水平方向)和Column(垂直方向)
线性布局可以将子Widget在同一个方向(水平或者垂直)上排列
Row的使用
效果图
使用方式:水平方向排列文本和图片
Row(
children: [
Text("我是文本"),
Image.asset(
"images/timg.jpeg",
width: 200,
)
],
)
下面来看下Row的构造方法:
Row({
Key key,
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
MainAxisSize mainAxisSize = MainAxisSize.max,
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
TextDirection textDirection,
VerticalDirection verticalDirection = VerticalDirection.down,
TextBaseline textBaseline,
List children = const [],
}) : super(
....
);
}
Column的使用
效果图
使用方式:垂直方向排列文本和图片
Column(
children: [
Text(
"我是文本",
style: TextStyle(fontSize: 24),
),
Image.asset(
"images/timg.jpeg",
width: 200,
)
],
),
构造函数
Column({
Key key,
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
MainAxisSize mainAxisSize = MainAxisSize.max,
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
TextDirection textDirection,
VerticalDirection verticalDirection = VerticalDirection.down,
TextBaseline textBaseline,
List children = const [],
}) : super(
...
);
}
看了Row和Column的构造函数我们可以看出来,跟Flex种的参数是想同的,实际上,它们都继承Flex,其实就是确定了主轴的Flex,所以用法和参数的含义跟Flex的一致,这里就不再进行重复介绍了。
- 流性布局 - Wrap:页面宽度按照屏幕分辨率适配调整,整体布局不变
Wrap布局会把超楚屏幕显示范围的Widget自动换行,下面看下效果图
下面看下Wrap布局的使用方法,上图的主要代码如下
Wrap(
children: [
Text(
"Hello world " * 100,
style: TextStyle(fontSize: 20),
)
],
)
接下来我们看另外一种常用的Wrap布局的显示
这种布局对于做Android开发到朋友应该都不陌生,很多带有热门标签的产品都会希望做成这种形式展示,在Flutter使用Wrap就能轻松实现
使用方式:
Wrap(
direction: Axis.horizontal,
spacing: 8.0,//主轴方向间距
runSpacing: 12.0,//交叉轴方向间距
alignment: WrapAlignment.center,
runAlignment: WrapAlignment.start,
children: [
Chip(
avatar: CircleAvatar(
backgroundColor: Colors.blue,child: Text("A"),
),
label: Text("AAAAAAAAAAAAA"),
),Chip(
avatar: CircleAvatar(
backgroundColor: Colors.blue,child: Text("B"),
),
label: Text("BBBBBBBBBBBB"),
),Chip(
avatar: CircleAvatar(
backgroundColor: Colors.blue,child: Text("C"),
),
label: Text("CCCCCC"),
),Chip(
avatar: CircleAvatar(
backgroundColor: Colors.blue,child: Text("D"),
),
label: Text("DDDDDDDDDDDDDDD"),
),Chip(
avatar: CircleAvatar(
backgroundColor: Colors.blue,child: Text("E"),
),
label: Text("EEEEEEEEEEEEEEEEEEEE"),
)
],
)
下面看下Wrap的构造函数
Wrap({
Key key,
this.direction = Axis.horizontal,//主轴方向,默认水平,类型Axis
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 children = const [],
}) : super(key: key, children: children);
其他未介绍的参数跟Flex中的参数意义相同。
- 层叠布局 - Stack(允许 子Widget 堆叠,子Widget 可以根据到父容器四个边的位置来确定本身的位置)
Stack是层叠布局,其子Widget会按照添加顺讯确定显示层级,后面添加的会覆盖在前面添加的Widget上面
先看下效果图
使用方式:
Stack(
children: [
Image.asset("images/timg.jpeg",),
Text("Hello Stack",
style: TextStyle(
fontSize: 48,
color: Colors.red,
backgroundColor: Colors.yellow
),)
],
)
Stack的子Widget
为了确定子Widget到容器四个角的位置,Stack将子Widget分为两类
1.positioned子Widget
指被Positioned嵌套起来的Widget,Positioned可以控制子Widget到父容器四个边的距离。
效果图
2.non - positioned子Widget
指不用Positioned嵌套起来的Widget,non-positioned子Widget使用Stack设置的alignment来确定自己在父容器里的位置。
效果图
实现方式:
Stack(
fit: StackFit.expand,
alignment: AlignmentDirectional.bottomEnd,
children: [
Positioned(
left: 50,
top: 100,
child: Image.asset("images/timg.jpeg",width: 200,),
),
Text("non-position widget",
style: TextStyle(
fontSize: 48,
color: Colors.red,
backgroundColor: Colors.yellow
),)
],
)
下面是Stack构造函数
Stack({
Key key,//
this.alignment = AlignmentDirectional.topStart,//决定子Widget如何对齐
this.textDirection,//用于确定 alignment 的对齐方向
this.fit = StackFit.loose,//此参数用于决定 non-positioned子Widget 如何去适应Stack的大小,类型StackFit
this.overflow = Overflow.clip,//决定如何显示超出 Stack显示空间的 子widget 类型Overflow
List children = const [],//Stack布局 里排列的内容
}) : super(key: key, children: children);
StackFit类型-3种方式
- StackFit.loose:使用 子Widget 自身的大小
- StackFit.expand:子Widget 扩伸到Stack的大小
- StackFit.passthrough:Stack的父Widget 的约束无修改的传递给 Stack的子Widget
AlignmentDirectional类型-9种方式
- AlignmentDirectional.topStart:上边 start 对齐
- AlignmentDirectional.topCenter:上边 居中 对齐
- AlignmentDirectional.topEnd:上边 end 对齐
- AlignmentDirectional.centerStart:中间 start 对齐
- AlignmentDirectional.center:中间 对齐
- AlignmentDirectional.centerEnd:中间 end 对齐
- AlignmentDirectional.bottomStart:下边 start 对齐
- AlignmentDirectional.bottomCenter:下边 居中 对齐
- AlignmentDirectional.bottomEnd:下边 end 对齐
Overflow-2种方式(如何显示超出 Stack显示空间的 子widget)
- Overflow.visible:超出部分仍能看见
- Overflow.clip:超出部分会被剪裁
Positioned构造函数
Positioned({
Key key,
this.left,//离 Stack 左边的距离
this.top,//离 Stack 上边的距离
this.right,//离 Stack 右边的距离
this.bottom,//离 Stack 底边的距离
this.width,//指定 Widget 的宽度
this.height,//指定 Widget 的高度
@required Widget child,//子Widget
}) : assert(left == null || right == null || width == null),
assert(top == null || bottom == null || height == null),
super(key: key, child: child);
关于Flutter中的 布局Widget就介绍完了
以下是我的Flutter系列的链接,后续会持续更新,欢迎大家指正。
Flutter 系列文章
- Flutter 学习 - 开篇
- Flutter 学习 - 基础框架
- Flutter 学习 - 网络请求和数据解析
- Flutter 学习 - Widget 之 Text
- Flutter 学习 - Widget 之 RichText
- Flutter 学习 - Widget 之 Image和Icon
- Flutter 学习 - Widget 之 TextField
- Flutter 学习 - Widget 之 菜单按钮
- Flutter 学习 - Widget 之 布局 Widget
- Flutter 学习 - 容器类Widget
- Flutter 学习 - 可滚动的 Widget
- Flutter 学习 - 功能类Widget
更多关于技术相关的内容请关注博主公众号--迷途程序猿