美文网首页
Flutter: Flow 九宫格

Flutter: Flow 九宫格

作者: LiYaoPeng | 来源:发表于2019-02-15 13:31 被阅读0次

    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<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 });
    }
    

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

    相关文章

      网友评论

          本文标题:Flutter: Flow 九宫格

          本文链接:https://www.haomeiwen.com/subject/rodyeqtx.html