一、Wrap
熟悉flex布局的同学肯定知道flex布局会有wrap属性,就是换行,而Flex、Column、Row都是不可以换行的。那么如果我们需要换行怎么办呢?Flutte提供了Wrap来解决这一需求,Wrap与Flex具有相似的属性。
构造函数
Wrap({
Key key,
this.direction = Axis.horizontal, // 主轴方向
this.alignment = WrapAlignment.start, //主轴方向上的对齐方式
this.spacing = 0.0, // 主轴方向上children的间隔
this.runAlignment = WrapAlignment.start, // children如何放置在交叉轴上
this.runSpacing = 0.0, // 交叉轴上children的间隔
this.crossAxisAlignment = WrapCrossAlignment.start, // children之间在交叉轴方向上的对齐方式
this.textDirection, // 水平开始的方向
this.verticalDirection = VerticalDirection.down, // 竖直的方向
List<Widget> children = const <Widget>[],
}) : super(key: key, children: children);
示例
import 'package:flutter/material.dart';
class WrapDemo extends StatelessWidget{
@override
Widget build(BuildContext context) {
Widget c1 = Container(
height: 130.0,
width: 130.0,
color: Colors.redAccent,
);
Widget c2 = Container(
height: 50.0,
width: 50.0,
color: Colors.lightBlueAccent,
);
Widget c3 = Container(
height: 80.0,
width: 80.0,
color: Colors.yellow,
);
Widget c4 = Container(
height: 100.0,
width: 100.0,
color: Colors.greenAccent,
);
Widget c5 = Container(
height: 170.0,
width: 170.0,
color: Colors.grey,
);
// TODO: implement build
return Container(
width: double.infinity,
height: double.infinity,
child: Wrap(
direction: Axis.horizontal,
spacing: 10.0,
runSpacing: 20.0,
alignment: WrapAlignment.center,
runAlignment: WrapAlignment.start,
crossAxisAlignment: WrapCrossAlignment.start,
verticalDirection: VerticalDirection.down,
textDirection: TextDirection.ltr,
children: <Widget>[c1, c2, c3, c4, c5],
),
);
}
}
Wrap的相关属性大部分与Flex类似,如alignment与Flex的mainAxisAlignment类似,都决定了在主轴方向上的对齐方式;crossAlignment与Flex的crossAxisAlignment相似,都决定了children在交叉轴上的对齐方式。这里主要对runAlignment与crossAlignment属性进行说明,runAlignment属性决定了children整体如何放置在交叉轴上,而crossAlignment属性决定了children之间在交叉轴方向上的对齐方式。详细效果参考如下:
runAlignment值 | 效果 |
---|---|
WrapAlignment.start | |
WrapAlignment.center | |
WrapAlignment.end | |
WrapAlignment.spaceBetween | |
WrapAlignment.spaceAround | |
WrapAlignment.spaceEvenly |
二、Flow
Flow可自定义children的排列布局,相对Wrap使用比较复杂。Flow中的delegate属性是自定义布局的关键,具体使用参考下面粒子。
import 'package:flutter/material.dart';
class FlowDemo extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return Flow(
delegate: TestFlowDelegate(margin:EdgeInsets.only(top: 10.0, left: 10.0)),
children: <Widget>[
Container(width: 80.0, height:80.0, color: Colors.red,),
Container(width: 80.0, height:80.0, color: Colors.green,),
Container(width: 80.0, height:80.0, color: Colors.blue,),
Container(width: 80.0, height:80.0, color: Colors.yellow,),
Container(width: 80.0, height:80.0, color: Colors.brown,),
Container(width: 80.0, height:80.0, color: Colors.purple,),
],
)
;
}
}
class TestFlowDelegate extends FlowDelegate{
EdgeInsets margin = EdgeInsets.zero;
TestFlowDelegate({this.margin});
@override
void paintChildren(FlowPaintingContext context) {
double x = margin.left;
double y = margin.top;
for (int i = 0; i < context.childCount; i++) {
double w = context.getChildSize(i).width + x + margin.right;
if (w < context.size.width) {
context.paintChild(i, transform: new Matrix4.translationValues(x, y, 0.0));
x = w + margin.left;
} else {
x = margin.left;
y += context.getChildSize(i).height + margin.top + margin.bottom;
context.paintChild(i, transform: new Matrix4.translationValues(x, y, 0.0));
x += context.getChildSize(i).width + margin.left + margin.right;
}
}
}
@override
bool shouldRepaint(FlowDelegate oldDelegate) {
// TODO: implement shouldRepaint
return oldDelegate != this;
}
}