Flutter(64):Layout组件之Flow

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;
  }
}
image.png

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的强大能力。

image.png

下一节:Layout组件之FlowTable

Flutter(65):Layout组件之FlowTable

Flutter教学目录持续更新中

Github源代码持续更新中

你可能感兴趣的:(Flutter(64):Layout组件之Flow)