Reputation: 1074
I am trying to build a custom version of a column (call it CustomColumn) that lays out the children lazily, similar to what a ListView would do but with more control on how exactly they are laid out. The most basic point I am stuck on is: How can I create a widget while in the performLayout phase of the CustomColumn. I am struggling to find a minimal example on how to do that. The only other widget I could find that does something like this is ListView but I could not create a minimal version of that.
During layout, I am trying to check the available space and, only if needed create a child (using an IndexedWidgetBuilder) and lay that out. I suppose that there should a functionality like 'adoptChild' or 'discardChild' to manage the child widget's lifecycle, but I could not find the correct API for that.
I am specifically not interested in scrolling, debug overflow painting, or anything beyond just dynamic (or lazy) widget creation during layout (for now). What could be the minimal set of classes needed to achieve this behaviour?
Upvotes: 1
Views: 163
Reputation: 44186
You want Boxy:
Boxy is a Flutter package created to overcome the limitations of built-in layout widgets, it provides utilities for flex, custom multi-child layouts, dynamic widget inflation, slivers, and more!
The package is ready for production use, it has excellent documentation, test coverage, and passes strict analysis.
Upvotes: 2
Reputation: 107
Without having a look at code it gonna be little hard to answer exact solution.I think you need to create 2 widgets first named as CustomColumn second you need LayoutWidget. some thing like that.
class CustomLazyColumn extends RenderObjectWidget {
final IndexedWidgetBuilder builder;
final int itemCount;
CustomLazyColumn({
Key? key,
required this.builder,
required this.itemCount,
}) : super(key: key);
@override
RenderObject createRenderObject(BuildContext context) {
return CustomLazyColumnRenderObject(
builder: builder,
itemCount: itemCount,
);
}
@override
void updateRenderObject(
BuildContext context, CustomLazyColumnRenderObject renderObject) {
renderObject
..builder = builder
..itemCount = itemCount;
}
}
after that use this rendering part
class CustomLazyColumnRenderObject extends RenderBox
with ContainerRenderObjectMixin<RenderBox, LazyColumnParentData> {
IndexedWidgetBuilder builder;
int itemCount;
CustomLazyColumnRenderObject({
required this.builder,
required this.itemCount,
});
double _currentOffset = 0.0;
@override
void performLayout() {
double usedHeight = 0.0;
double maxWidth = 0.0;
RenderBox? child = firstChild;
for (int index = 0; index < itemCount; index++) {
if (usedHeight >= constraints.maxHeight) break;
if (child == null) {
// Create the child lazily
final newChild = builder(null, index).createRenderObject(context!);
adoptChild(newChild);
insert(newChild);
child = newChild;
}
child.layout(constraints, parentUsesSize: true);
final childParentData = child.parentData as LazyColumnParentData;
childParentData.offset = Offset(0, _currentOffset);
_currentOffset += child.size.height;
usedHeight += child.size.height;
maxWidth = maxWidth.max(child.size.width);
child = childAfter(child);
}
size = constraints.constrain(Size(maxWidth, usedHeight));
}
@override
void paint(PaintingContext context, Offset offset) {
RenderBox? child = firstChild;
while (child != null) {
final childParentData = child.parentData as LazyColumnParentData;
context.paintChild(child, offset + childParentData.offset);
child = childAfter(child);
}
}
@override
void setupParentData(RenderBox child) {
if (child.parentData is! LazyColumnParentData) {
child.parentData = LazyColumnParentData();
}
}
}
class LazyColumnParentData extends ContainerBoxParentData {}
hopefully it gonna help
CustomLazyColumn(
itemCount: 1000,
builder: (context, index) {
return Text('Item $index', style: TextStyle(fontSize: 18));
},
);
Upvotes: 0