I'm trying to create a gridview which works like Stagarredgridview.count but without using any package, i've created it using CustomMultichildLayout but i can't make it scrollable. I know i can use any scrollable like singlechildscrollview or listview for this.
The main problem is infinite height which i can't seem to resolve, i've tried layout builder,expanded and flexible widgets for constraints even boxconstraints from Container but can't resolve infinite height.
Here's the code
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Column(
children: [
Expanded(
child: OrganicGrid(count: 50),
),
],
),
);
}
}
class OrganicGrid extends StatelessWidget {
final int count;
const OrganicGrid({
required this.count,
super.key,
});
@override
Widget build(BuildContext context) {
return CustomGrid(
children: List.generate(count, (index) => ContainerWidget(id: index + 1)),
);
}
}
class ContainerWidget extends StatelessWidget {
final int id;
const ContainerWidget({
required this.id,
super.key,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Container(
height: 50,
decoration: const BoxDecoration(
color: Colors.green,
// border: Border.all(color: Colors.red, width: 2),
),
child: Center(
child: Text(
"Text $id",
style: TextStyle(color: Colors.white),
)),
),
);
}
}
class CustomGrid extends StatelessWidget {
final List<Widget> children;
const CustomGrid({required this.children, super.key});
@override
Widget build(BuildContext context) {
List<Widget> rows = [];
bool oddExist = children.length % 2 != 0;
if (oddExist) {
rows.add(LayoutId(id: 0, child: children[0]));
}
if (oddExist) {
for (int i = 1; i < children.length; i++) {
rows.add(LayoutId(id: i, child: children[i]));
}
} else {
for (int i = 1; i <= children.length; i++) {
rows.add(LayoutId(id: i, child: children[i - 1]));
}
}
return CustomMultiChildLayout(
key: key,
delegate: CustomGridDelegate(numRows: rows.length, oddExist: oddExist),
children: rows,
);
}
}
class CustomGridDelegate extends MultiChildLayoutDelegate {
final int numRows;
final bool oddExist;
CustomGridDelegate({required this.numRows, required this.oddExist});
@override
void performLayout(Size size) {
const double padding = 8;
double width = size.width - padding * 3;
double childHeight = 60;
double dy = 0;
double dx = padding;
void childLayout(int i) {
positionChild(i, Offset(dx, dy));
layoutChild(
i,
BoxConstraints(minWidth: width / 2, maxWidth: width / 2),
);
if (i % 2 == 0) {
dy += childHeight;
dx = padding;
} else {
dx = width / 2;
dx += padding * 2;
}
}
void zerothChildLayout(int i) {
positionChild(i, Offset(dx, dy));
layoutChild(
0,
BoxConstraints(minWidth: width + padding),
);
dy += childHeight;
}
if (oddExist) {
zerothChildLayout(0);
for (int i = 1; i < numRows; i++) {
childLayout(i);
}
} else {
for (int i = 1; i <= numRows; i++) {
childLayout(i);
}
}
}
@override
bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) => false;
}
I've tried layoutbuilder,boxconstraints,expanded,flexible and similar widets without success, the only way it work is by wraping with fixed size container but that is not dynamic.
Any help would be appreciated, you can directly try this code by pasting.