美文网首页
Flutter 小部件 流式布局、自动换行(Wrap、Flow)

Flutter 小部件 流式布局、自动换行(Wrap、Flow)

作者: 程序员阿兵 | 来源:发表于2020-10-22 09:21 被阅读0次

    文章目录

    流式布局

    流式布局在移动端是非常常见的,比如商品列表,瀑布流、标签页等等。使用Android原生来实现流式布局还是有点麻烦的,甚至需要自定义view或者使用第三方的库。而在Flutter中,官方为我们提供了流式布局的控件,我们可以很方便的实现流式布局。

    Wrap

    首先来看Wrap,Wrap是一个可以使子控件自动换行的控件,默认的方向是水平的,使用起来非常简单。

    构造方法

    Wrap({
        Key key,
        this.direction = Axis.horizontal,   //排列方向,默认水平方向排列
        this.alignment = WrapAlignment.start,  //子控件在主轴上的对齐方式
        this.spacing = 0.0,  //主轴上子控件中间的间距
        this.runAlignment = WrapAlignment.start,  //子控件在交叉轴上的对齐方式
        this.runSpacing = 0.0,  //交叉轴上子控件之间的间距
        this.crossAxisAlignment = WrapCrossAlignment.start,   //交叉轴上子控件的对齐方式
        this.textDirection,   //textDirection水平方向上子控件的起始位置
        this.verticalDirection = VerticalDirection.down,  //垂直方向上子控件的其实位置
        List<Widget> children = const <Widget>[],   //要显示的子控件集合
      })
    

    下面我们就来简单的用一用:

    import 'package:flutter/material.dart';
    
    /*
    * 可以让子控件自动换行的控件
    *
    * */
    class WrapWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Wrap(
          spacing: 2, //主轴上子控件的间距
          runSpacing: 5, //交叉轴上子控件之间的间距
          children: Boxs(), //要显示的子控件集合
        );
      }
    
    
      /*一个渐变颜色的正方形集合*/
      List<Widget> Boxs() => List.generate(10, (index) {
            return Container(
              width: 100,
              height: 100,
              alignment: Alignment.center,
              decoration: BoxDecoration(
                gradient: LinearGradient(colors: [
                  Colors.orangeAccent,
                  Colors.orange,
                  Colors.deepOrange
                ]),
              ),
              child: Text(
                "${index}",
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 20,
                  fontWeight: FontWeight.bold,
                ),
              ),
            );
          });
    }
    
    
    image.png

    Flutter中的流式布局是不是非常简单。

    Flow

    Flow用起来远比Wrap麻烦,但是它可以实现更加个性化的需求,我们可以通过delegate属性自己设置子控件排列规则。

    构造方法

    Flow({
        Key key,
        @required this.delegate,   //布局委托,接收一个FlowDelegate类型的值
        List<Widget> children = const <Widget>[],  //要显示的子控件
      })
    

    我们主要来看看delegate属性,他接收一个FlowDelegate类型的值

    FlowDelegate

    FlowDelegate是一个抽象类,我们一般会重写paintChildren方法,在该方法中,我们可以来控制子控件的摆放。


    image.png

    下面我们来简单用一用:
    主要要实现paintChildren中的方法

    import 'package:flutter/material.dart';
    
    /*
    * 流式布局
    * 自定义FlowDelegate
    * */
    
    double boxSize = 80.0;
    
    class FlowWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Flow(
          delegate: MyFlowDelegate(),
          children: List.generate(10, (index) {
            return Box(index);
          }),
        );
      }
    
      /*一个带渐变颜色的正方形*/
      Widget Box(index) => Container(
            width: boxSize,
            height: boxSize,
            alignment: Alignment.center,
            decoration: BoxDecoration(
              gradient: LinearGradient(
                  colors: [Colors.orangeAccent, Colors.orange, Colors.deepOrange]),
            ),
            child: Text(
              index.toString(),
              style: TextStyle(
                color: Colors.white,
                fontSize: 20,
                fontWeight: FontWeight.bold,
              ),
            ),
          );
    }
    
    class MyFlowDelegate extends FlowDelegate {
      @override
      void paintChildren(FlowPaintingContext context) {
        /*屏幕宽度*/
        var screenW = context.size.width;
    
        double padding = 5; //间距
        double offsetX = padding; //x坐标
        double offsetY = padding; //y坐标
    
        for (int i = 0; i < context.childCount; i++) {
          /*如果当前x左边加上子控件宽度小于屏幕宽度  则继续绘制  否则换行*/
          if (offsetX + boxSize < screenW) {
            /*绘制子控件*/
            context.paintChild(i,
                transform: Matrix4.translationValues(offsetX, offsetY, 0));
            /*更改x坐标*/
            offsetX = offsetX + boxSize + padding;
          } else {
            /*将x坐标重置为margin*/
            offsetX = padding;
            /*计算y坐标的值*/
            offsetY = offsetY + boxSize + padding;
            /*绘制子控件*/
            context.paintChild(i,
                transform: Matrix4.translationValues(offsetX, offsetY, 0));
          }
        }
      }
    
      @override
      bool shouldRepaint(FlowDelegate oldDelegate) {
        return true;
      }
    }
    
    
    
    image.png

    在正常情况下,能用wrap就用wrap,实现其来比较简单,如果是比较个性化的排列规则,可以使用Flow来实现。
    好了,Flutter流式布局大概就是这样。

    相关文章

      网友评论

          本文标题:Flutter 小部件 流式布局、自动换行(Wrap、Flow)

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