Flutter: Flow 九宫格

Flow需要自己实现子widget的位置转换,在很多场景下首先要考虑的是Wrap是否满足需求。Flow主要用于一些需要自定义布局策略或性能要求较高(如动画中)的场景。

Flow有如下优点:

  1. 性能好;Flow是一个对child尺寸以及位置调整非常高效的控件,Flow用转换矩阵(transformation matrices)在对child进行位置调整的时候进行了优化:在Flow定位过后,如果child的尺寸或者位置发生了变化,在FlowDelegate中的paintChildren()方法中调用context.paintChild 进行重绘,而context.paintChild在重绘时使用了转换矩阵(transformation matrices),并没有实际调整Widget位置。
  2. 灵活;由于我们需要自己实现FlowDelegate的paintChildren()方法,所以我们需要自己计算每一个widget的位置,因此,可以自定义布局策略。

缺点:

  1. 使用复杂.
  2. 不能自适应子widget大小,必须通过指定父容器大小或实现TestFlowDelegate的getSize返回固定大小。

Flow

 Flow({
    Key key,
    @required this.delegate,/// delegate 用于布局childWidget
    List children = const [],/// 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 });
}

Matrix4

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: [
            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详解

你可能感兴趣的:(Flutter: Flow 九宫格)