Container
容器控件,可以添加一个子控件,设置宽度高度,padding
,margin,背景色、背景图、圆角、阴影 等属性,基本包含了容器控件的常用基本属性。
有些widget 自带padding
属性,所以不必多套一层Padding部件。(比如ListView、GridView、Container、ScrollView、Button )
基本使用:
Widget build(BuildContext context) {
return MaterialApp(
home: Container(
width: 200.0,
height: 150.0,
margin: const EdgeInsets.fromLTRB(25, 15, 0, 0),
padding: const EdgeInsets.fromLTRB(10, 15, 10, 15),
alignment: const Alignment(0, 0),
decoration: const BoxDecoration(boxShadow: [
//卡片阴影
BoxShadow(
color: Colors.black54,
offset: Offset(5.0, 5.0),
blurRadius: 7.0)
]),
child: Image.network(
"https://gips3.baidu.com/it/u=2498623727,1870741620&fm=3030&app=3030&f=JPEG?w=200&h=133&s=F31330C442402557123E451103005099",
width: 200.0,
height: 150.0,
)),
);
}
常用属性:
width:宽度,如果设置具体值则为具体值,不设置则包裹子控件大小,设置为double.infinity一般会充满父控件或者充满屏幕(如果没有其他特别的约束条件);
height:高度,使用方法基本同width;
margin:设置控件与其他控件的外边距;
padding:设置内边距;
decoration:背景装饰;
alignment:设置子控件的方位,用Alignment属性值来表示,具体对应的方位如下:
Alignment topLeft = Alignment(-1.0, -1.0);
Alignment topCenter = Alignment(0.0, -1.0);
Alignment topRight = Alignment(1.0, -1.0);
Alignment centerLeft = Alignment(-1.0, 0.0);
Alignment center = Alignment(0.0, 0.0);
Alignment centerRight = Alignment(1.0, 0.0);
Alignment bottomLeft = Alignment(-1.0, 1.0);
Alignment bottomCenter = Alignment(0.0, 1.0);
Alignment bottomRight = Alignment(1.0, 1.0);
Column(纵向布局) and Row(横向布局)
Column(纵向布局)
类似iOS中的 tableview
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("学习demo"),
),
body: const Column(
mainAxisAlignment: MainAxisAlignment.start, //主轴方向上控件排列规则(居中 靠边 均匀分布等) 主轴是指竖直列表
crossAxisAlignment: CrossAxisAlignment.start, //纵轴方向上控件排列规则(start左 center居中 end靠右边等)
mainAxisSize: MainAxisSize.max, //主轴方向(纵向)占空间尽量大,(如果没有其他特别的约束条件则要么填满屏幕,要么填满父布局)
verticalDirection:VerticalDirection.down, //控件顺序正常顺序,VerticalDirection.up则倒叙
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
Text('verticalDirection:VerticalDirection.up'),
Text('crossAxisAlignment: CrossAxisAlignment.center'),
Text('mainAxisAlignment: MainAxisAlignment.spaceEvenly'),
Text('textBaseline: TextBaseline.ideographic'),
],
),
//ZTListTitleView()
);
}
Row(横向布局)
和纵向布局属性差不多 要注意元素超出屏幕的控制
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("学习demo"),
),
body: Row(
mainAxisSize:
MainAxisSize.max, //主轴方向(横向)占空间尽量大,(如果没有其他特别的约束条件则要么填满屏幕,要么填满父布局)
verticalDirection: VerticalDirection.down, //实测 up和down效果一样
crossAxisAlignment: CrossAxisAlignment.center, //纵轴方向(纵向)上控件排列规则(居中 靠边等)
mainAxisAlignment: MainAxisAlignment.spaceBetween, ////主轴方向上控件排列规则(居中 靠边 均匀分布等)
textBaseline: TextBaseline.ideographic,
textDirection: TextDirection.ltr, //从左到右排列
children: <Widget>[
Container(color: Colors.blue[100], width: 70, height: 70),
Container(color: Colors.blue[200], width: 70, height: 70),
Container(color: Colors.blue[300], width: 70, height: 70),
Container(color: Colors.blue[400], width: 70, height: 70),
],
),
//ZTListTitleView()
);
}
合并介绍
这里mainAxis和crossAxis代表主轴方向和纵轴方向,Row(横向布局)主轴方向就是横向,纵轴方向就是纵向;Column(纵向布局)主轴方向就是纵向,纵轴方向就是横向;
几个常用属性:
mainAxisSize:
- MainAxisSize.max:主轴方向占空间尽量大,(如果没有其他特别的约束条件则要么填满屏幕,要么填满父布局);
- MainAxisSize.min:主轴方向占空间尽量小,基本就是包裹子控件的尺寸了
textDirection
- TextDirection.ltr,从左到右排列;
- TextDirection.rtl,从右到左排列;
textBaseline
- TextBaseline.alphabetic,使用按照排列字母字符的基准线排列方式
- TextBaseline.ideographic,使用按照表意字字符的基准线排列方式(比如中文);
表意字好像是说可以拆解结构的文字类型,通过各种部首的组合可以形成各种文字,例如中文。(这里有一个视频,简单了解什么是表意字)
verticalDirection
- VerticalDirection.up,从下向上排列;
- VerticalDirection.down,从上向下排列;
mainAxisAlignment:
- start:将children放置在主轴的起点;
- center:将children放置在主轴的中心;
- end:将children放置在主轴的末尾;
- spaceAround:将主轴方向上的空白区域均分,使得children之间的空白区域相等,但是首尾child的空白区域为1/2;
- spaceBetween:将主轴方向上的空白区域均分,使得children之间的空白区域相等,首尾child都靠近首尾,没有间隙;
- spaceEvenly:将主轴方向上的空白区域均分,使得children之间的空白区域相等,包括首尾child;
crossAxisAlignment:
- start:将children放置在纵轴的起点;
- center:将children放置在纵轴的中心;
- end:将children放置在纵轴的末尾;
Wrap 流式布局
Wrap包裹子控件,也可以设置横向和纵向,它与Row和Column的区别在于:Row和Column只有一行或一列,子控件尺寸超出了就会显示不全,但是Wrap会自动换行。
Widget build(BuildContext context) {
return Wrap(
direction: Axis.horizontal,
//start end值受textDirection具体值的影响
alignment: WrapAlignment.start,
runAlignment: WrapAlignment.center, //纵轴方向对齐方式
spacing: 15, //主轴方向间距15
runSpacing: 10, //纵轴方向间距10
textDirection: TextDirection.ltr,
children: <Widget>[
Container(
color: Colors.green[100],
width: 70,
height: 70,
),
Container(color: Colors.green[200], width: 70, height: 70),
Container(color: Colors.green[300], width: 180, height: 70),
Container(color: Colors.green[400], width: 70, height: 70),
Container(
color: Colors.green[100],
width: 70,
height: 70,
),
Container(color: Colors.green[200], width: 70, height: 70),
Container(color: Colors.green[300], width: 70, height: 70),
Container(color: Colors.green[400], width: 70, height: 70),
],
);
}
常用属性:direction:排列方向
Axis.horizontal 横向布局(主轴为横向)
Axis.vertical 纵向布局(主轴为纵向)
alignment:使用WrapAlignment的属性值,但是含义和Row、Column基本一致;
spacing:主轴方向子控件间距;
runSpacing:纵轴方向的间距(主轴是横向则纵轴是纵向,主轴是纵向则纵轴是横向);
runAlignment:纵轴方向的对齐方式;
注意 :crossAxisAlignment和runAlignment都表示纵轴方式的对齐方式,实测的结果似乎crossAxisAlignment并没有起作用,只有runAlignment起作用了
Stack 重叠布局
可以把子控件叠在一起来展示。Stack可以搭配Positioned控件一起使用,Positioned控件可以控制子控件在Stack中的具体位置(设置距离左上右下的具体参数)和控件大小(设置宽高),使用场景会非常多
Widget build(BuildContext context) {
return Stack(
fit: StackFit.loose,
alignment: AlignmentDirectional.center,
textDirection: TextDirection.ltr,
children: <Widget>[
Container(
width: 120,
height: 120,
color: Colors.cyan[200],
),
Container(
width: 90,
height: 90,
color: Colors.cyan[400],
),
Container(
width: 60,
height: 60,
color: Colors.cyan[600],
),
Positioned(
left: 100,
top: 100,
child: Container(
width: 220,
height: 220,
color: Colors.cyan[800],
),
) //指定位置,超出stack范围,测试overflow属性
],
);
}
常用属性:
alignment:设置子控件的方位,用AlignmentDirectional的值来表示,这个类里面的start和end受textDirection具体值的影响,TextDirection.ltr(左到右)对应start为左边,,TextDirection.rtl(右到左)对应start为右边,属性值具体对应的方位如下
AlignmentDirectional topStart = AlignmentDirectional(-1.0, -1.0);
AlignmentDirectional topCenter = AlignmentDirectional(0.0, -1.0);
AlignmentDirectional topEnd = AlignmentDirectional(1.0, -1.0);
AlignmentDirectional centerStart = AlignmentDirectional(-1.0, 0.0);
AlignmentDirectional center = AlignmentDirectional(0.0, 0.0);
AlignmentDirectional centerEnd = AlignmentDirectional(1.0, 0.0);
AlignmentDirectional bottomStart = AlignmentDirectional(-1.0, 1.0);
AlignmentDirectional bottomCenter = AlignmentDirectional(0.0, 1.0);
AlignmentDirectional bottomEnd = AlignmentDirectional(1.0, 1.0);
fit:子控件适应Stack控件尺寸的方式,这个属性对于非Positioned控件内的子控件起作用。
StackFit.loose:使用此属性时,对于非Positioned控件内的子控件,它的尺寸会小于Stack控件的尺寸,比如Stack的尺寸是300x600,那么子控件的尺寸宽度允许在0到300之间,高度允许在0到600之间;
StackFit.expand:使用此属性时,对于非Positioned控件内的子控件,它的尺寸会撑满Stack的尺寸。比如Stack的尺寸是300x600,那么子控件的尺寸宽度会是300,高度会是600;
StackFit.passthrough:对子控件的约束条件直接由Stack的父控件传递给Stack的子控件;
GridView
网格布局,类似于iOS的UICollectionView
Widget build(BuildContext context) {
return GridView(
scrollDirection: Axis.vertical,
reverse: false,
// primary: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, //横轴三个子widget
childAspectRatio: 1.3 //宽高比为1
),
children: <Widget>[
Container(
color: Colors.blue[300],
margin: EdgeInsets.fromLTRB(5, 5, 5, 5),
width: 70,
height: 70,
),
Container(
color: Colors.blue[300],
margin: EdgeInsets.fromLTRB(5, 5, 5, 5),
width: 70,
height: 70,
),
Container(
color: Colors.blue[300],
margin: EdgeInsets.fromLTRB(5, 5, 5, 5),
width: 70,
height: 70,
),
Container(
color: Colors.blue[300],
margin: EdgeInsets.fromLTRB(5, 5, 5, 5),
width: 70,
height: 70,
),
Container(
color: Colors.blue[300],
margin: EdgeInsets.fromLTRB(5, 5, 5, 5),
width: 70,
height: 70,
),
Container(
color: Colors.blue[300],
margin: EdgeInsets.fromLTRB(5, 5, 5, 5),
width: 70,
height: 70,
),
],
);
}
scrollDirection: 滚动方向,Axis.vertical(竖直方向);Axis.horizontal(水平方向);
reverse:子控件排序是否反转;
controller: 滚动控制器,监听和控制滚动用到,比如写下拉加载更多之类的功能就可以用到这个。可以参考ScrollController 滚动监听及控制。
shrinkWrap:该属性表示是否根据子组件的总长度来设置GridView的长度,默认值为false 。默认情况下,GridView的会在滚动方向尽可能多的占用空间。当GridView在一个无边界(滚动方向上)的容器中时,shrinkWrap必须为true。
gridDelegate: 控制子控件排列规则的参数,包括配置子控件横纵方向间距,纵轴方向子控件个数,子控件宽高比例等参数,详细文档参考GridView。
ListView
1. ListView.builder
ListView.builder(
itemCount: data.length,
itemExtent: 50.0, //强制高度为50.0
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text("$index"));
}
);
itemBuilder作为列表项的布局构建器,具体构建每个位置上的item布局,并展示相应的内容。itemCount配置列表的item条数,可以根据具体的数据来灵活配置。
2. ListView.separated
相对于ListView.builder,ListView.separated增加了一个分割线的构造器separatorBuilder,分割线在实际开发中也是很常用到的。
ListView.separated(
itemBuilder: (BuildContext context, int index) {
return Container(
height: 60,
child: TextButton(
onPressed: () {},
child: Text(
"哈哈",
)));
},
separatorBuilder: (BuildContext context, int index) {
return Container(
height: 1,
color: Color(0xffe2e8ed),
);
},
itemCount: 39),
ListView主要属性:
itemExtent: 此参数如果不为null,则会强制children的“长度”为itemExtent的值;这里的“长度”是指滚动方向上子组件的长度,也就是说如果滚动方向是垂直方向,则itemExtent代表子组件的高度;如果滚动方向为水平方向,则itemExtent就代表子组件的宽度。在ListView中,指定itemExtent比让子组件自己决定自身长度会更高效,这是因为指定itemExtent后,滚动系统可以提前知道列表的长度,而无需每次构建子组件时都去再计算一下,尤其是在滚动位置频繁变化时(滚动系统需要频繁去计算列表高度);
itemCount: item条数;
itemBuilder、separatorBuilder的作用在上面代码中都能看得比较清晰;
其他的包括scrollDirection、reverse、controller、shrinkWrap、addRepaintBoundaries、addAutomaticKeepAlives等等这些基本上和GridView是一样的,直接参考上面GridView就可以了。
SingleChildScrollView
单一子控件的滚动布局,跟Android的ScrollView基本一样,Android的ScrollView也是只能有一个子控件,不然就会报错。
基本使用很简单:
Widget build(BuildContext context) {
return SingleChildScrollView(
scrollDirection: Axis.vertical,
reverse:false,
controller:controller,
child: Column(
children: <Widget>[
//...
],
),
);
}
InkWell
InkWell有的叫溅墨效果,有的叫水波纹效果。使用场景是给一些无点击事件的部件添加点击事件时使用(也支持长按、双击等事件),同时你也可以去修改它的颜色和形状。
InkWell(
borderRadius: BorderRadius.circular(8.0), // 圆角
splashColor: Colors.transparent, // 溅墨色(波纹色)
highlightColor: Colors.transparent, // 点击时的背景色(高亮色)
onTap: () {},// 点击事件
child: Container(),
);
不过有时你会发现并不是包一层InkWell就一定会有溅墨效果。主要原因是溅墨效果是在一个背景效果,并不是覆盖的前景效果。所以InkWell中的child一旦有设置背景图或背景色,那么就会遮住这个溅墨效果。如果你需要这个溅墨效果,有两种方式实现。
1、包一层 Material,将背景色设置在 Material中的color里。
Material(
color: Colors.white,
child: InkWell(),
)
2、使用Stack布局,将InkWell放置在上层。这种适用于给图片添加点击效果,比如Banner图的点击。
Stack(
children: <Widget>[
Positioned.fill(
child: Image(),
),
Positioned.fill(
child: Material(
color: Colors.transparent,
child: InkWell(
splashColor: Color(0X40FFFFFF),
highlightColor: Colors.transparent,
onTap: () {},
),
),
)
],
)