在flutter中渲染对象的performlayout函数期间以编程方式创建小部件?

问题描述 投票:0回答:1

我正在尝试构建一个自定义版本的列(称为 CustomColumn),它可以惰性地布置子项,类似于 ListView 的功能,但可以更好地控制它们的布置方式。我所坚持的最基本的一点是:如何在 CustomColumn 的 PerformLayout 阶段创建一个小部件。我正在努力寻找一个关于如何做到这一点的最小示例。我能找到的唯一一个能做类似事情的小部件是 ListView,但我无法创建它的最小版本。

在布局期间,我尝试检查可用空间,并且仅在需要时创建一个子项(使用 IndexedWidgetBuilder)并将其布局。我认为应该有像“adoptChild”或“discardChild”这样的功能来管理子小部件的生命周期,但我找不到正确的 API。

我对滚动、调试溢出绘画或布局期间动态(或惰性)小部件创建之外的任何内容(目前)特别不感兴趣。实现此行为所需的最小类集是什么?

flutter dart layout rendering
1个回答
0
投票

如果不看代码,就很难回答确切的解决方案。 我认为您需要创建 2 个小部件,首先命名为 CustomColumn,然后您需要 LayoutWidget。类似的事情。

class CustomColumn extends StatefulWidget {
  final IndexedWidgetBuilder itemBuilder;
  final int itemCount;

  CustomColumn({required this.itemBuilder, required this.itemCount});

  @override
  _CustomColumnState createState() => _CustomColumnState();
}

class _CustomColumnState extends State<CustomColumn> {
  @override
  Widget build(BuildContext context) {
    return CustomMultiChildLayout(
      delegate: _CustomColumnLayoutDelegate(widget.itemCount, widget.itemBuilder),
      children: List.generate(widget.itemCount, (index) {
        return LayoutId(
          id: index,
          child: Container(), 
        );
      }),
    );
  }
}

之后你需要MultiChildLayout

class _CustomColumnLayoutDelegate extends MultiChildLayoutDelegate {
  final int itemCount;
  final IndexedWidgetBuilder itemBuilder;

  _CustomColumnLayoutDelegate(this.itemCount, this.itemBuilder);

  @override
  void performLayout(Size size) {
    double yOffset = 0.0;
    for (int i = 0; i < itemCount; i++) {
      // Create the child widget lazily
      final child = itemBuilder(context, i);
      if (child is! SizedBox) {
        // Wrap the child in a SizedBox to get its size
        final childSize = child is RenderBox ? child.size : Size.zero;
        if (yOffset + childSize.height <= size.height) {
          // Layout the child if there's enough space
          layoutChild(i, BoxConstraints.tightFor(width: size.width, height: childSize.height));
          positionChild(i, Offset(0, yOffset));
          yOffset += childSize.height;
        } else {
          // Break if there's no more space
          break;
        }
      }
    }
  }

  @override
  bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) {
    return true; // Always relayout for simplicity
  }
}

并像这样在任何地方使用它

CustomColumn(
          itemCount: 100,
          itemBuilder: (context, index) {
            return Container(
              height: 50,
              color: index.isEven ? Colors.blue : Colors.green,
              child: Center(child: Text('Item $index')),
            );
          },
        ),
      )

我已经为这种功能开发了一个基本包。你可以查看这个包的文档或github,这个包通过使用包中的SpacedColumn和SpacedRow小部件来维护列和行之间的空间。

https://pub.dev/packages/equal_space
© www.soinside.com 2019 - 2024. All rights reserved.