Flutter 中拥有需要将近30种内置的 布局Widget,其中常用有 Container、Padding、Center、Flex、Stack、Row、Column、ListView 等,下面简单讲解它们的特性和使用。
概述
Container
给一个组件添加padding,margins,边界(borders),背景颜色或其它装饰(decorations)。
GridView
将多个widget放在一个可滑动的表格中
ListView
将多个widget放在一个可滑动列表中
Stack
在一个widget上面覆盖另外一个widget
Material Components
只有Material App能够使用Material Components的组件。
Card
将一些相近的信息封装进一个有圆角的阴影的盒子里。
ListTile
一个Row中装载最多3行文字,可选则在前面或者尾部添加图标。
Container
最常用的默认布局,只能包含一个child,支持配置padding,margin,color,width,height,decoration(一般配置边框和阴影)等配置,在Flutter中,不是所有的控件都有宽高、padding、margin、color等属性,所以才会有Padding,Center等Widget的存在。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
Container(
//四周10大小的margin
margin: EdgeInsets.all(10.0),
height: 120.0,
width: 500.0,
//透明黑色遮罩
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(4.0)),
color: Colors.black,
border: Border.all(color: Colors.blue,width: 0.3)
),
child: Text("6666",
style: TextStyle(color: Colors.red),),
),
|
decoration: Decorations.bottom, 底部横线
Column、Row
它们常用的有这些属性配置:主轴方向是 start 或 center 等;副轴方向方向是 start 或 center 等;mainAxisSize 是充满最大尺寸,或者只根据子 Widget 显示最小尺寸。
日常使用场景配置:
1
2
3
4
5
6
|
//主轴方向,Column的竖向、Row我的横向
mainAxisAlignment: MainAxisAlignment.start,
//默认是最大充满、还是根据child显示最小大小
mainAxisSize: MainAxisSize.max,
//副轴方向,Column的横向、Row我的竖向
crossAxisAlignment :CrossAxisAlignment.center,
|
Expanded
在Column和Row中代表平均充满,当又两个存在的时候,默认平均充满,同事可以设置flex属性决定比例。
1
2
3
4
5
6
7
8
9
10
11
12
|
Column(
//主轴居中,即竖直向居中
mainAxisAlignment: MainAxisAlignment.center,
//大小按照最小显示
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
///flex默认值为1
Expanded(child: Center(child:Text("1111")),flex: 2,),
Expanded(child: Text("222"),),
],
)
|
ListView
childrenDelegate:自定义子模型时用到。
itemExtent:Item 的范围,scrollDirection 为 Axis.vertical 时限制高度,scrollDirection 为 Axis.horizontal 限制宽度。
cacheExtent:预加载的区域。
controller:滑动监听,值为一个 ScrollController 对象,这个属性应该可以用来做下拉刷新和上垃加载,后面详细研究。
padding:整个 ListView 的内间距。
physics:设置 ListView 如何响应用户的滑动行为,值为一个 ScrollPhysics 对象,它的实现类常用的有:
- AlwaysScrollableScrollPhysics:总是可以滑动。
- NeverScrollableScrollPhysics:禁止滚动。
- BouncingScrollPhysics:内容超过一屏,上拉有回弹效果。
- ClampingScrollPhysics:包裹内容,不会有回弹,感觉跟 AlwaysScrollableScrollPhysics 差不多。
primary:是否是与 PrimaryScrollController 关联的主滚动视图,若为 true 则 controller 必须为空。
reverse:Item 的顺序是否反转,若为 true 则反转。
scrollDirection:ListView 的方向,为 Axis.vertical 表示纵向,为 Axis.horizontal 表示横向。
shrinkWrap:不太明白。
itemCount:子 Item 数量,只有使用 new ListView.builder() 和 new ListView.separated() 构造方法的时候才能指定,其中 new ListView.separated() 是必须指定。
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
|
ListView.separated(
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.only(left: 10.0,right: 10.0),
padding: EdgeInsets.only(left: 10.0,right: 10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10.0),),
color: Colors.white
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
child: Text(
"这是一点描述",
style: TextStyle(color: Colors.grey, fontSize: 14.0,),
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
margin: EdgeInsets.only(top: 6.0, bottom: 2.0),
alignment: Alignment.topLeft,
),
Padding(padding: EdgeInsets.all(10.0),),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_getBottomItem(Icons.star, "1000"),
_getBottomItem(Icons.link, "1000"),
_getBottomItem(Icons.subject, "1000"),
],
)
],
)
);
},
itemCount: 20,
separatorBuilder: (context,index){
return Divider(color: Colors.transparent);
},
),
|
GridView
用GridView来将widget放入一个2维的列表中。
GridView提供了2个预装配的列表,也可以在自己建立自定义的列表。
- 将多个widget放进一个表格中
- 当超出渲染范围是,自动提供滚动功能
- 可自定义格子,也可以用下面提供的两种
- GridView.count 指定列的数目
- GridView.extent 允许指定子项的最大像素宽度
示例1 用GridView.extent
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
|
import 'package:flutter/material.dart';
class GridDemo1Page extends StatefulWidget {
@override
State<StatefulWidget> createState() => new _GridDemo1PageState();
}
class _GridDemo1PageState extends State<GridDemo1Page> {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text('Grid Page 1 demo'),),
body: new Center(
child: buildGrid(),
),
);
}
List<Container> _buildGridTileList(int count) {
return new List<Container>.generate(count, (int index) =>
new Container(child: new Image.asset('images/pic${index + 1}.jpg'),));
}
Widget buildGrid() {
return new GridView.extent(
maxCrossAxisExtent: 150.0,
padding: const EdgeInsets.all(4.0),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
children: _buildGridTileList(30),);
}
}
|

示例二-用GridView.count
1
2
3
4
5
6
7
8
9
10
11
|
Widget buildGrid() {
var countGrid = GridView.count(
crossAxisCount: 2,
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
padding: const EdgeInsets.all(4.0),
childAspectRatio: 1.3,
children: _buildGridTileList(30),
);
return countGrid;
}
|

Stack
使用Stack在widget之上显示另一些widget,通常用来显示图片。
显示的widget可以完全地把底部widget盖住。
- 用力啊在当前widget上面再盖上一层widget
- Stack children 中第一个widget放在最下面,后面的widget会一层层盖上去
- stack的内容不支持滚动
- 可以裁剪超过范围的自widget
示例
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
|
import 'package:flutter/material.dart';
class StackPage1 extends StatefulWidget {
@override
State<StatefulWidget> createState() => new _StackPage1State();
}
class _StackPage1State extends State<StackPage1> {
@override
Widget build(BuildContext context) {
var stack = new Stack(
alignment: const Alignment(0.6, 0.6),
children: <Widget>[
new CircleAvatar(
backgroundImage: new AssetImage('images/android_1.jpg'),
radius: 100.0,),
new Container(decoration: new BoxDecoration(color: Colors.black45),
child: new Text(
'Android Avatar', style: new TextStyle(color: Colors.white70),),),
new Container(decoration: new BoxDecoration(color: Colors.transparent),
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 100.0, 0.0),
child: new CircleAvatar(
backgroundImage: new AssetImage('images/p_box1.png'),
backgroundColor: Colors.transparent,
radius: 10.0,),),
],
);
return new Scaffold(
appBar: new AppBar(title: new Text('Stack Demo 1'),),
body: new Center(child: stack,),
);
}
}
|

Card
Card来自Material组件库,可包含一些数据,通常用ListTile来组装。Card只有一个子widget,可以是column、row、list、grid或其它组合widget。
默认情况下,Card把自己的尺寸缩小为0像素。可以用SizedBox来指定card的尺寸。
Flutter中的Card有圆角和阴影效果。修改elevation可改变阴影效果。
elevation取值范围,参考 Elevation and Shadows
若设置范围外的值,阴影效果会消失。
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
|
import 'package:flutter/material.dart';
class ListViewPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => new _ListViewPageState();
}
class _ListViewPageState extends State<ListViewPage> {
@override
Widget build(BuildContext context) {
List<Widget> list = <Widget>[];
for (int i = 0; i < 30; i++) {
list.add(new Card(child: new Column(
children: <Widget>[
new Image.asset(
'images/pic${i + 1}.jpg',),
new ListTile(
title: new Text('title$i', style: _itemTextStyle,),
subtitle: new Text('A'),
leading: i % 3 == 0
? new Icon(Icons.theaters, color: Colors.blue,)
: new Icon(Icons.restaurant, color: Colors.blue,),
),
],
),));
}
return new Scaffold(
appBar: new AppBar(title: new Text('ListView Demo'),),
body: new Center(child: new ListView(children: list,),),
);
}
}
TextStyle _itemTextStyle = new TextStyle(
fontWeight: FontWeight.w500, fontSize: 14.0);
|
