flutter CustomMultiChildLayout 自定义控件实现图片瀑布流效果

CustomMultiChildLayout允许我们通过delegate自定义子组件的布局约束、位置以及父组件的大小(父组件大小不依赖于子组件的情况下),和CustomSingleChildLayout基本一样,区别就是CustomSingleChildLayout包裹一个子控件,而CustomMultiChildLayout包裹多个。
接下来我会用CustomMultiChildLayout 控件实现一个图片瀑布流墙的效果,效果如下:

图片瀑布流 img
在这里插入图片描述

CustomMultiChildLayout控件需要两个重要参数
一、delegate 具体处理子控件的代理
二、children 子控件集合

子控件必须被LayoutId 控件包裹起来,因为这样才可以找到它。

创建子控件
    final items = List.generate(20, (index) {
      int ys = index % 8+1;
      return LayoutId(
          id: "id_$index",
          child: Container(
            width: 100,
            height: 40 + Random().nextDouble() * 100,
            color: Colors.red[100*ys],
            child: FlutterLogo(),//替换成你的图片控件
          ));
    });

为了看到效果我们这里把高度和颜色都弄成随机, id 则是子控件唯一标识。

然后使用控件:

CustomMultiChildLayout(
            delegate: ProxyClass(items.length, 3, 5),
            children: items,
          )

这里ProxyClass 是实现效果的具体方法:

class ProxyClass extends MultiChildLayoutDelegate {
  int num;
  int columnNum;
  int padding;

  ProxyClass(this.num, this.columnNum, this.padding);

  @override
  void performLayout(Size size) {
    double lastWidth = size.width - columnNum * padding;
    double itemWidth = lastWidth / columnNum;
    double offsetX = 0;
    List columnH = List.generate(columnNum, (index) {
      return 0.0;
    });
    for (int i = 0; i < num; i++) {
      int ys = i % columnNum;
      print("$ys === ${columnH[ys]}");
      Size itemSize = layoutChild(
          "id_$i",
          BoxConstraints(
              minWidth: itemWidth,
              maxWidth: itemWidth,
              minHeight: 0,
              maxHeight: 1000));
      positionChild("id_$i", Offset(offsetX+padding*0.5, columnH[ys]));
      offsetX += padding + itemWidth;
      if (offsetX >= size.width - 1) {
        offsetX = 0;
      }
      columnH[ys] += itemSize.height + padding;
      print("size : ${columnH[ys]}----$offsetX");
    }
  }

  @override
  bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) {
    return true;
  }
}

主要通过id查找每个具体的子控件,columnNum是竖直方向一共多少列,padding是每个模块的间隙。
shouldRelayout是告诉系统每次刷新是是否重绘,我们这里写的是每次都需要重绘。
performLayout 则是具体布局实现方法,size是 自定义控件的具体大小。
layoutChild 通过给子控件设置约束来获取子控件大小。
positionChild 是布局子控件位置的方法。

上面逻辑主要是通过计算每个子控件的offset来排版成瀑布流的样子。

如果对你有帮助记得点赞哦 !!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值