前言
Flutter 的布局在此前的文章多多少少用过,但是没有具体讲过,Flutter 的布局实际上也由 Widget 来控制的,在 Flutter 官网上并没有对布局 Widget 进行分类,这里将布局 Widget 根据子元素排列方式分为以下几种:
- 线性布局 Widget
- 流式布局 Widget
- 层式布局 Widget
- 弹性布局 Widget
下面分别介绍这几种布局 Widget。
1. 线性布局 Widget
线性布局类似于 Android 中的 LinearLayout,可以垂直也可以水平排列,Flutter 的线性布局有两个:
- Row:水平方向的线性布局。
- Column:垂直方向的线性布局。
Row 和 Column 的使用方法类似,举个 Row 的例子,Column 自然而然也就会了。
import 'package:flutter/material.dart';
void main() => runApp(RowWidget());
class RowWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter",
home: Scaffold(
appBar: AppBar(
title: Text("Row示例"),
),
body: Padding(
padding: EdgeInsets.all(40.0),
child: Row(
children: <Widget>[
Text("Android进阶之光"),
Text("Android进阶解密"),
],
),
),
),
);
}
}
效果如下图所示。
2. 流式布局 Widget
流式布局就是把超出屏幕显示范围的控件自动换行,在 Android 中并没有现成的流式布局控件,都是开发人员自己封装的,比如鸿洋封装的 FlowLayout。Flutter 中提供了 Wrap 来实现流式布局。
import 'package:flutter/material.dart';
void main() => runApp(ChipWidget());
class ChipWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter",
home: Scaffold(
appBar: AppBar(
title: Text("流式布局示例"),
),
body: Padding(
padding: EdgeInsets.all(20.0),
child: Wrap(
direction: Axis.horizontal, //主轴的方向
spacing: 8.0, // 主轴方向的间距
runSpacing: 12.0, // 交叉轴方向的间距
children: <Widget>[
Chip(//1
avatar: CircleAvatar(
backgroundColor: Colors.blue, child: Text('1')),
label: Text('Android进阶之光'),
),
Chip(
avatar: CircleAvatar(
backgroundColor: Colors.blue, child: Text('2')),
label: Text('Android进阶解密'),
),
Chip(
avatar: CircleAvatar(
backgroundColor: Colors.blue, child: Text('3')),
label: Text('Android进阶?'),
),
],
),
),
),
);
}
}
注释 1 处的 Chip 意为碎片,实际上是一个标签 Widget,这个例子中定义了三个标签来体现流式布局。
Wrap 有很多属性,它的构造函数如下:
Wrap({
Key key,
this.direction = Axis.horizontal, //1
this.alignment = WrapAlignment.start,//2
this.spacing = 0.0,
this.runAlignment = WrapAlignment.start,
this.runSpacing = 0.0,
this.crossAxisAlignment = WrapCrossAlignment.start,
this.textDirection,
this.verticalDirection = VerticalDirection.down,
List<Widget> children = const <Widget>[],
}) : super(key: key, children: children);
注释 1 处的 direction 属性,它用于设定主轴的方向(子 Widget 排列的方向),默认值为 Axis.horizontal,部分属性见下表:
参数名称 | 参数类型 | 含义 |
---|---|---|
direction | Axis | 主轴的方向 |
alignment | WrapAlignment | 子 Widget 在主轴上的对齐方式 |
runAlignment | WrapAlignment | 每行或每列的对齐方式 |
runSpacing | double | 每行或每列之间的间距 |
crossAxisAlignment | WrapCrossAlignment | 子 Widget 在交叉轴上的对齐方式 |
textDirection | TextDirection | 子 Widget 在主轴方向上的布局顺序 |
verticalDirection | VerticalDirection | 子 Widget 在交叉轴方向上的布局顺序 |
运行后的效果如下图所示。
3. 层式布局 Widget
层式布局类似于 Android 的 FrameLayout,在 Flutter 可以通过 Stack 来实现层式布局,其子 Widget 会按照添加顺序确定显示层级,后面添加的会覆盖在前面添加的 Widget 上面。
为了确定子 Widget 到父容器四个角的位置,Stack 将子 Widget 分为两类:
- positioned:Positioned 嵌套的子 Widget,Positioned 可以控制子 Widget 到父容器四个边的距离。
- non-positioned :没有用 Positioned 嵌套起来的子 Widget,使用 Stack 的 alignment 属性来控制自身在父容器里的位置。
import 'package:flutter/material.dart';
void main() => runApp(StackWidget());
class StackWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter",
home: Scaffold(
appBar: AppBar(
title: Text("层式布局示例"),
),
body: Stack(
fit: StackFit.expand,
children: <Widget>[
Positioned(
left: 90.0,
top: 120.0,
child: Image.asset(
"images/decode.png",
width: 200.0,
fit: BoxFit.cover,
),
),
Container(
child: Text('Android进阶三部曲第二部',
style: TextStyle(
color: Colors.lightBlue, fontSize: 20.0)),
height: 50.0,
width: 100.0,
alignment: Alignment.center,
)
],
),
),
);
}
}
上面的代码中,Stack 分为两个部分,一个是 Positioned Widget,用于显示一个图片,一个是 non-positioned Widget,嵌套在 Container 中,用于显示一行文字。效果如下图所示。
4. 弹性布局 Widget
Flutter 中的弹性布局是 Flex,类似于 Android 中的 FlexboxLayout。为了避免子 Widget 在 Flex、Row、Column 中超界,可以使用 Flexible 和 Expanded,它们可以让 Flex、Row、Column 的子 Widget 具有弹性能力,下面以 Flex 和 Expanded 搭配使用作为例子。
import 'package:flutter/material.dart';
void main() => runApp(FlexWidget());
class FlexWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter",
home: Scaffold(
appBar: AppBar(
title: Text("弹性布局示例"),
),
body: Flex(
direction: Axis.horizontal,//1
children: <Widget>[
Expanded(
flex: 1,
child: Container(
height: 60.0,
width: 30.0,
color: Colors.red,
),
),
Expanded(
flex: 3,
child: Container(
height: 60.0,
width: 30.0,
color: Colors.yellow,
),
),
Expanded(
flex: 1,
child: Container(
height: 60.0,
width: 30.0,
color: Colors.blue,
),
),
],
),
),
);
}
}
注释 1 处的 direction 属性,用于设置主轴的方向,这是必须要设置的。Flex 的子 Widget 是三个 Expanded,每个 Expanded 负责显示一个矩形色块,用 flex 来设置弹性系数,三个矩形色块的比例为 1:3:1,效果如下图所示。
总结
本文介绍了 Flutter 中布局 Widget 分类,实际上对于每个布局分类都可以写一篇文章,这里都做了简化,带领大家快速入门。如果你想了解更多,可以查看文档或者直接查看各种 Widget 的源码。
文章评论