1.Flex
Flex可以沿着水平或垂直方向排列子widget,如果你知道主轴方向,使用Row或Column会方便一些,因为Row和Column都继承自Flex,参数基本相同,所以能使用Flex的地方一定可以使用Row或Column
Flex({
...
@required this.direction, //弹性布局的方向, Row默认为水平方向,Column默认为垂直方向
List<Widget> children = const <Widget>[],
})
//一般用Row和Column比较多
2.Expanded 类似于web里面的flex属性功能
可以按比例“扩伸”Row、Column和Flex子widget所占用的空间
flex为弹性系数,如果为0或null,则child是没有弹性的,即不会被扩伸占用的空间。如果大于0,所有的Expanded按照其flex的比例来分割主轴的全部空闲空间
const Expanded({
int flex = 1, // 类似于web的flex属性
@required Widget child,
})
示例1:
Widget _rowLeft(){
return Row(
textDirection: TextDirection.ltr, //默认就是ltr
mainAxisAlignment: MainAxisAlignment.spaceBetween, //由左向右,所以end是最右边
children: <Widget>[
Text("目录1"),
Expanded(child: Container(child: Text("目录2"),width: 100.0,color: Colors.blueAccent,),flex: 1,),
Text("目录3")
],
);
}
示例2:
Widget _rowLeft(){
return Row(
textDirection: TextDirection.ltr, //默认就是ltr
mainAxisAlignment: MainAxisAlignment.spaceBetween, //由左向右,所以end是最右边
children: <Widget>[
Expanded(child: Container(child: Text("目录1"),width: 100.0,color: Colors.redAccent,),flex: 1,),
Expanded(child: Container(child: Text("目录2"),width: 100.0,color: Colors.blueAccent,),flex: 2,),
Text("目录3")
],
);
}
3.wrap
在介绍Row和Colum时,如果子widget超出屏幕范围,则会报溢出错误
可以看到,右边溢出部分报错。这是因为Row默认只有一行,如果超出屏幕不会折行。我们把超出屏幕显示范围会自动折行的布局称为流式布局
属性类似Row和Column
Wrap({
...
this.direction = Axis.horizontal, //row还是column
this.alignment = WrapAlignment.start, //主轴对齐方式
this.spacing = 0.0, // 主轴方向子widget的间距
this.runAlignment = WrapAlignment.start, /* wrap的每行(列)在整个在父级里面交叉轴的对齐方式
this.runSpacing = 0.0, // run的间距
this.crossAxisAlignment = WrapCrossAlignment.start,
this.textDirection,
this.verticalDirection = VerticalDirection.down,
List<Widget> children = const <Widget>[],
})
Widget _wrap() {
return Container(child: Wrap(
// alignment: WrapAlignment.center, //默认是start
direction: Axis.horizontal,
spacing: 2.0,
runSpacing: 1.0,
crossAxisAlignment: WrapCrossAlignment.end, //交叉轴每行里面子集的对齐方式
runAlignment: WrapAlignment.spaceBetween, //每整行(整体)在父级的对齐方式(交叉轴,目前是纵轴)
children: <Widget>[
Container(
child: Text("目录1"),
width: 100.0,
color: Colors.blueAccent,
),
Container(
child: Text("目录2"),
width: 50.0,
color: Colors.teal,
),
Container(
child: Text("目录3"),
width: 160.0,
height: 150.0,
color: Colors.redAccent,
),
Container(
child: Text("目录4"),
width: 100.0,
color: Colors.yellowAccent,
),
Container(
child: Text("目录2"),
width: 50.0,
height: 100.0,
color: Colors.teal,
),
Container(
child: Text("目录3"),
width: 100.0,
height: 150.0,
color: Colors.redAccent,
),
],
),
decoration: BoxDecoration(border: Border.all(width: 1.0,color: Colors.amberAccent)),
height: 350.0,
);
}
4.层叠布局
Flutter中使用Stack和Positioned来实现绝对定位,Stack允许子widget堆叠,而Positioned可以给子widget定位(根据Stack的四个角)
Stack({
this.alignment = AlignmentDirectional.topStart, //此参数决定如何去对齐没有定位(没有使用
Positioned)或部分定位的子widget
//所谓部分定位,在这里特指没有在某一个轴上定位:left、right为横轴,top、bottom为纵轴,只要包含某
个轴上的一个定位属性就算在该轴上有定位
this.textDirection, //和Row、Wrap的textDirection功能一样,都用于决定alignment对齐的参考系即:textDirection的值为TextDirection.ltr,则alignment的start代表左,end代表右,即从左往右的顺序;textDirection的值为TextDirection.rtl,则alignment的start代表右,end代表左,即从右往左的顺序
this.fit = StackFit.loose, //此参数用于决定没有定位的子widget如何去适应Stack的大小。StackFit.loose表示使用子widget的大小,StackFit.expand表示扩伸到Stack的大小
this.overflow = Overflow.clip, // 属性决定如何显示超出Stack显示空间的子widget,值为Overflow.clip时,超出部分会被剪裁(隐藏),值为Overflow.visible 时则不会
List<Widget> children = const <Widget>[],
})
const Positioned({
Key key,
this.left,
this.top,
this.right,
this.bottom,
this.width,
this.height,
@required Widget child,
})
//Left、top 、right、 bottom分别代表离Stack左、上、右、底四边的距离
//width和height用于指定定位元素的宽度和高度,注意,此处的width、height 和其它地方的意义稍微有点区别,此处用于配合left、top 、right、 bottom来定位widget
//举个例子,在水平方向时,你只能指定left、right、width三个属性中的两个,如指定left和width后,right会自动算出(left+width),如果同时指定三个属性则会报错,垂直方向同理
Widget _pos(){
return Container(
child: Stack(children: <Widget>[
Text("没有定位的元素"), //没有定位 所以是Alignment.centerRight
// Text("没有定位的元素2"), //这个会重叠在上面Text上面
Positioned(child: Text("定位Left"),left: 20.0,), //没有定义Y轴上的,所以是部分定位,沿用alignment的Y轴center
Positioned(child: Text("完全定位"),left: 20.0,top:20.0), //完全定位
],
alignment: Alignment.centerRight,
),
width: 300.0,
height: 400.0,
decoration: BoxDecoration(
border: Border.all(width: 2.0,color: Colors.blueAccent)
),
);
}
Widget _pos() {
return Container(
child: Stack(
children: <Widget>[
Text("没有定位的元素"), //没有定位 所以是Alignment.centerRight
// Text("没有定位的元素2"), //这个会重叠在上面Text上面
Positioned(
child: Text("定位Left"),
left: 20.0,
), //没有定义Y轴上的,所以是部分定位,沿用alignment的Y轴center
Positioned(child: Text("完全定位"), left: 20.0, top: 20.0), //完全定位
Container(
child: Text("Hello world", style: TextStyle(color: Colors.white)),
color: Colors.red,
),
Positioned(child: Text("覆盖在最后能展示的"), left: 60.0, top: 60.0), //完全定位
],
alignment: Alignment.centerRight,
fit: StackFit.expand, //未定位widget占满Stack整个空间
),
width: 300.0,
height: 400.0,
decoration: BoxDecoration(
border: Border.all(width: 2.0, color: Colors.blueAccent)),
);
}