Flutter教学目录持续更新中
Github源代码持续更新中
1.Flow介绍
一个实现流式布局算法的widget
用法跟CustomSingleChildLayout很像,但是比CustomSingleChildLayout更加强大
2.Flow属性
- delegate:FlowDelegate
- children = const
[]:
3.FlowDelegate
- void paintChildren(FlowPaintingContext context):这个方法是用来绘制子组件的
- Size getSize(BoxConstraints constraints):获取父容器约束条件确定Flow大小
- bool shouldRepaint(covariant FlowDelegate oldDelegate):是否需要重绘
- BoxConstraints getConstraintsForChild(int i, BoxConstraints constraints):确定child的约束
- bool shouldRelayout(FlowDelegate oldDelegate):是否需要relayout
4.FlowPaintingContext
- size:可以用来绘制的空间大小
- childCount:子组件数量
- getChildSize(int i):获取子组件
- paintChild(int i, { Matrix4 transform, double opacity = 1.0 }):绘制子组件,默认从左上角开始
可以看到这里绘制是用Matrix4绘制的,那么他将可以实现移动,缩放,旋转,扭曲等一系列的矩阵变换。Matrix4这个在之前介绍过:Flutter(59):Layout组件之Transform
5.使用
_myChildren() {
return [
Container(
color: Colors.cyan,
width: 80,
height: 50,
),
Container(
color: Colors.red,
width: 150,
height: 50,
),
Container(
color: Colors.yellow,
width: 200,
height: 50,
),
Container(
color: Colors.blue,
width: 300,
height: 50,
),
Container(
color: Colors.grey,
width: 110,
height: 50,
),
Container(
color: Colors.green,
width: 180,
height: 50,
),
];
}
body: Flow(
delegate: _MyFlowDelegate(),
children: _myChildren(),
),
class _MyFlowDelegate extends FlowDelegate {
@override
void paintChildren(FlowPaintingContext context) {
var dx = 0.0;
var dy = 0.0;
for (int i = 0; i < context.childCount; i++) {
if (dx + context.getChildSize(i).width < context.size.width) {
} else {
dx = 0;
dy += context.getChildSize(i).height;
}
context.paintChild(
i,
transform: Matrix4.compose(
Vector.Vector3(dx, dy, 0),
Vector.Quaternion(0, 0, 0, 0),
Vector.Vector3(1, 1, 1),
),
);
dx += context.getChildSize(i).width;
}
}
@override
Size getSize(BoxConstraints constraints) {
//获取父容器约束条件确定Flow大小
print('getSize constraints = $constraints');
return super.getSize(constraints);
}
@override
bool shouldRepaint(covariant FlowDelegate oldDelegate) {
return false;
}
@override
BoxConstraints getConstraintsForChild(int i, BoxConstraints constraints) {
//确定child的约束,用于确定child的大小
print('getConstraintsForChild constraints = $constraints ');
return super.getConstraintsForChild(i, constraints);
}
@override
bool shouldRelayout(FlowDelegate oldDelegate) {
//是否需要relayout
return false;
}
}
Flow支持按你想要的方式去实现布局,例如这里判断每行剩余空间是否能放下子控件,放不下就换行绘制。当然了这里写的比较简单,只是给大家提供一下简单的演示。
我们之前也看到了,FlowPaintingContext绘制是使用的Matrix4,那么也就是说我们可以通过一个变量来改变Matrix4的属性达到让Flow子控件运动起来的效果,下面我们来试一下:
AnimationController _animationController;
double scale = 0;
@override
void initState() {
_animationController = AnimationController(
duration: Duration(milliseconds: 3000), vsync: this);
_animationController.addListener(() {
setState(() {
scale = _animationController.value * 2;
print("scale = $scale");
});
});
_animationController.forward();
super.initState();
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
class _MyAnimFlowDelegate extends FlowDelegate {
_MyAnimFlowDelegate(this.scale);
final double scale;
@override
void paintChildren(FlowPaintingContext context) {
for (int i = 0; i < context.childCount; i++) {
context.paintChild(
i,
transform: Matrix4.compose(
Vector.Vector3(0, 0, 0),
Vector.Quaternion(0, 0, 0, 0),
Vector.Vector3(scale, scale, 1),
),
);
}
}
@override
Size getSize(BoxConstraints constraints) {
//获取父容器约束条件确定Flow大小
print('getSize constraints = $constraints');
return super.getSize(constraints);
}
@override
bool shouldRepaint(covariant FlowDelegate oldDelegate) {
return true;
}
@override
BoxConstraints getConstraintsForChild(int i, BoxConstraints constraints) {
//确定child的约束,用于确定child的大小
print('getConstraintsForChild constraints = $constraints ');
return super.getConstraintsForChild(i, constraints);
}
@override
bool shouldRelayout(FlowDelegate oldDelegate) {
//是否需要relayout
return false;
}
}
body: Flow(
delegate: _MyAnimFlowDelegate(scale),
children: [
Container(
width: 50,
height: 50,
decoration:
BoxDecoration(color: Colors.red, shape: BoxShape.circle),
),
InkWell(
onTap: () {
_animationController.reset();
_animationController.forward();
},
)
],
),
这里实现的效果很简单,就是使用一个AnimationController控制器,让一个红色圆实现放大效果,InkWell是添加一个点击事件。由于本教程对动画还没有讲解到,这里就不再做比较难的特效了,目的只是为了演示Flow的强大能力。
下一节:Layout组件之FlowTable