Flow需要自己实现子widget的位置转换,在很多场景下首先要考虑的是Wrap是否满足需求。Flow主要用于一些需要自定义布局策略或性能要求较高(如动画中)的场景。
Flow有如下优点:
- 性能好;Flow是一个对child尺寸以及位置调整非常高效的控件,Flow用转换矩阵(transformation matrices)在对child进行位置调整的时候进行了优化:在Flow定位过后,如果child的尺寸或者位置发生了变化,在FlowDelegate中的paintChildren()方法中调用context.paintChild 进行重绘,而context.paintChild在重绘时使用了转换矩阵(transformation matrices),并没有实际调整Widget位置。
- 灵活;由于我们需要自己实现FlowDelegate的paintChildren()方法,所以我们需要自己计算每一个widget的位置,因此,可以自定义布局策略。
缺点:
- 使用复杂.
- 不能自适应子widget大小,必须通过指定父容器大小或实现TestFlowDelegate的getSize返回固定大小。
Flow
Flow({
Key key,
@required this.delegate,/// delegate 用于布局childWidget
List<Widget> children = const <Widget>[],/// childWidget集合
})
FlowDelegate
用于回调
Flow
大小,以及 计算childWidget
的frame。
///设置Flow的尺寸;
Size getSize(BoxConstraints constraints) => constraints.biggest;
/// 是否需要重新布局。
bool shouldRelayout(covariant FlowDelegate oldDelegate) => false;
///设置每个child的布局约束条件,会覆盖已有的;
BoxConstraints getConstraintsForChild(int i, BoxConstraints constraints) => constraints;
/// child的绘制控制代码,可以调整尺寸位置;
void paintChildren(FlowPaintingContext context);
/// 是否需要重绘;
bool shouldRepaint(covariant FlowDelegate oldDelegate);
FlowPaintingContext
包装了一些布局child的必要数据 以及 child布局方法
abstract class FlowPaintingContext {
/// 获取childWidget可以绘制的最大的范围,这个值取决于Flow的大小
Size get size;
/// 获取childWidget的个数
int get childCount;
/// 获取第i个childWidget的大小
Size getChildSize(int i);
/// 用矩阵Matrix4布局childWidget
void paintChild(int i, { Matrix4 transform, double opacity = 1.0 });
}
scale:缩放比例
transform: 移动
rotationZ:绕Z轴旋转
rotationX:绕X轴旋转
rotationY:绕Y轴旋转
columns:设置一个新的矩阵
compose:复合平移、旋转、缩放,形成新的状态
copy:复制一个4*4的张量(矩阵)
demo
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' as Vector;
void main() {
runApp(MaterialApp(
home: MyApph(),
));
}
class MyApph extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("搜索记录"),
),
body: Flow(
delegate: TestFlowDelegate(margin: EdgeInsets.all(10.0)),
children: <Widget>[
new Container(width: 80.0, height: 80.0, color: Colors.red),
new Container(width: 80.0, height: 80.0, color: Colors.yellow),
new Container(width: 80.0, height: 80.0, color: Colors.green),
new Container(width: 80.0, height: 80.0, color: Colors.blue),
new Container(width: 80.0, height: 80.0, color: Colors.lightBlue),
new Container(width: 80.0, height: 80.0, color: Colors.black),
new Container(width: 80.0, height: 80.0, color: Colors.blueGrey),
new Container(width: 80.0, height: 80.0, color: Colors.brown),
new Container(width: 80.0, height: 80.0, color: Colors.black12),
],
));
}
}
class TestFlowDelegate extends FlowDelegate {
EdgeInsets margin = EdgeInsets.zero;
TestFlowDelegate({this.margin});
@override
void paintChildren(FlowPaintingContext context) {
var x = margin.left;
var y = margin.top;
//计算每一个子widget的位置
for (int i = 0; i < context.childCount; i++) {
var w = context.getChildSize(i).width + x + margin.right;
if (w < context.size.width) {
context.paintChild(
i,
transform: new Matrix4.compose(Vector.Vector3(x,y,0.0), Vector.Quaternion(0.0,0.0,0.3,0.1), Vector.Vector3(1.0,1.0,1.0))
);
x = w + margin.left;
} else {
x = margin.left;
y += context.getChildSize(i).height + margin.top + margin.bottom;
//绘制子widget(有优化)
context.paintChild(i,
transform: Matrix4.translationValues(x, y, 0.0) //位移
);
x += context.getChildSize(i).width + margin.left + margin.right;
}
}
}
getSize(BoxConstraints constraints) {
//指定Flow的大小
return Size(double.infinity, double.infinity);
}
@override
bool shouldRepaint(FlowDelegate oldDelegate) {
return oldDelegate != this;
}
}
Flow
flutter布局-5-Matrix4矩阵变换
Flutter 布局(九)- Flow、Table、Wrap详解
网友评论