Flutter 开发实战

235课时
1K学过
8分

课程评价 (0)

请对课程作出评价:
0/300

学员评价

暂无精选评价
2分钟

13 CustomMultiChildLayout-2

childSize 相信大家都能故名思义,那 childId 是什么呢?

这就要从 MultiChildLayoutDelegate 的实现说起,MultiChildLayoutDelegate 内部会有一个 Map _idToChild; 对象,这个 Map 对象保存着 Object idRenderBox 的映射关系,而在 MultiChildLayoutDelegate 中获取 RenderBox 都需要通过 id 获取。

_idToChild 这个 Map 是在 RenderBox performLayout 时,在 delegate._callPerformLayout 方法内创建的,创建后所用的 idMultiChildLayoutParentData 中的 id, MultiChildLayoutParentData 的 id ,可以通过 LayoutId 嵌套时自定义指定赋值。

而完成上述布局,我们需要知道每个 child 的 index ,所以我们可以把 index 作为 id 设置给每个 child 的 LayoutId

所以我们可以通过 LayoutId 指定 id 为数字 index , 同时告知 delegate ,这样我们就知道 child 顺序和位置啦。

这个 id 是 Object 类型 ,所以你懂得,你可以赋予很多属性进去。

如下代码所示,这样在自定义的 CircleLayoutDelegate 中,就知道每个控件的 index 位置,也就是知道了,圆形布局中每个 item 需要的位置。

我们只需要通过 index ,计算出 child 所在的角度,然后利用 layoutChildpositionChild 对每个item进行布局即可,完整代码:GSYFlutterDemo

///自定义实现圆形布局
class CircleLayoutDelegate extends MultiChildLayoutDelegate {
  final List<String> customLayoutId;

  final Offset center;

  Size childSize;

  CircleLayoutDelegate(this.customLayoutId,
      {this.center = Offset.zero, this.childSize});

  @override
  void performLayout(Size size) {
    for (var item in customLayoutId) {
      if (hasChild(item)) {
        double r = 100;

        int index = int.parse(item);

        double step = 360 / customLayoutId.length;

        double hd = (2 * math.pi / 360) * step * index;

        var x = center.dx + math.sin(hd) * r;

        var y = center.dy - math.cos(hd) * r;

        childSize ??= Size(size.width / customLayoutId.length,
            size.height / customLayoutId.length);

        ///设置 child 大小
        layoutChild(item, BoxConstraints.loose(childSize));

        final double centerX = childSize.width / 2.0;

        final double centerY = childSize.height / 2.0;

        var result = new Offset(x - centerX, y - centerY);

        ///设置 child 位置
        positionChild(item, result);
      }
    }
  }

  @override
  bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) => false;
}

总的来说,第二种实现方式相对简单,但是也丧失了一定的灵活性,可自定义控制程度更低,但是也更加规范与间接,同时我们自己实现 RenderBox 时,也可以用类似的 delegate 的方式做二次封装,这样的自定义布局会更行规范可控。