Open robertsLando opened 4 years ago
The same issue when anything state related happens, e.g. with Flutter Redux, dispatching an action will cause a re-render.
@robertsLando I resolved this by changing the approach to match that of ListView.builder
and using the IndexedWidgetBuilder
to create the children widgets.
I had to do a similar trick to make this work
@andreaselia Hi, can you post a sample code with your solution? I will be really grateful
@andreaselia Hi, can you post a sample code with your solution? I will be really grateful
Sorry @kawi15, I no longer have access to the code and unfortunately don't remember what my comment above even referred to. Perhaps @robertsLando could help?
@kawi15 just as I wrote that my iCloud search came back with something (I assumed I had nothing in there, but I have a copy of the code, I think). Give it a try and let me know, I haven't used this in years.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class MasonryGrid extends StatefulWidget {
MasonryGrid({
this.column = 1,
this.mainAxisSpacing = 0,
this.crossAxisSpacing = 0,
this.crossAxisAlignment = CrossAxisAlignment.stretch,
this.staggered = false,
required this.data,
required this.itemBuilder,
});
final int column;
final double mainAxisSpacing;
final double crossAxisSpacing;
final CrossAxisAlignment crossAxisAlignment;
final bool staggered;
final List data;
final IndexedWidgetBuilder itemBuilder;
@override
_MasonryGrid createState() => _MasonryGrid();
}
class _MasonryGrid extends State<MasonryGrid> {
int renderId = 0;
late List<List<Widget>> columnItem;
late List<GlobalKey> columnKey;
@override
void initState() {
assert(widget.column >= 1, 'column should be at least 1.');
assert(widget.mainAxisSpacing >= 0, 'mainAxisSpacing should be positive.');
assert(widget.crossAxisSpacing >= 0, 'crossAxisSpacing should be positive.');
columnItem = List.generate(widget.column, (i) => []);
columnKey = List.generate(widget.column, (i) => GlobalKey());
super.initState();
}
@override
void didUpdateWidget(prev) {
if (!listEquals(prev.data, widget.data) || prev.column != widget.column || prev.mainAxisSpacing != widget.mainAxisSpacing || prev.crossAxisSpacing != widget.crossAxisSpacing || prev.crossAxisAlignment != widget.crossAxisAlignment || prev.staggered != widget.staggered) {
setState(() {
renderId = 0;
columnItem = List.generate(widget.column, (i) => []);
columnKey = List.generate(widget.column, (i) => GlobalKey());
});
}
super.didUpdateWidget(prev);
}
int getSmallestColumnId() {
var smallestColumnId = 0;
try {
final renderColumn = List<RenderBox?>.generate(columnKey.length, (i) => columnKey[i].currentContext?.findRenderObject() as RenderBox?);
final columnHeight = List<double>.generate(renderColumn.length, (i) => renderColumn[i]!.size.height);
columnHeight.asMap().forEach((i, item) {
if (columnHeight[i] < columnHeight[smallestColumnId]) {
smallestColumnId = i;
}
});
} catch (err) {
// TODO: handle err.
}
return smallestColumnId;
}
void renderItemStaggered() {
var columnId = getSmallestColumnId();
columnItem[columnId].add(Padding(
padding: EdgeInsets.only(bottom: widget.mainAxisSpacing),
child: widget.itemBuilder(context, renderId),
));
setState(() {
renderId = renderId + 1;
});
}
void renderItemInOrder() {
for (var i = renderId; i < widget.data.length; i++) {
columnItem[i % widget.column].add(Padding(
padding: EdgeInsets.only(bottom: widget.mainAxisSpacing),
child: widget.itemBuilder(context, i),
));
}
setState(() {
renderId = widget.data.length;
});
}
void renderChildren() {
if (!widget.staggered && renderId < widget.data.length) {
renderItemInOrder();
} else if (widget.staggered && renderId < widget.data.length) {
Future.microtask(() => renderItemStaggered());
}
}
@override
Widget build(BuildContext context) {
renderChildren();
final column = widget.crossAxisSpacing == 0
? List.generate(
widget.column,
(i) => Expanded(
child: Column(
key: columnKey[i],
crossAxisAlignment: widget.crossAxisAlignment,
children: columnItem[i],
),
),
)
: List.generate(
widget.column + (widget.column - 1),
(i) => i.isEven
? Expanded(
child: Column(
key: columnKey[(i / 2).floor()],
crossAxisAlignment: widget.crossAxisAlignment,
children: columnItem[(i / 2).floor()],
),
)
: SizedBox(
width: widget.crossAxisSpacing,
),
);
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: column,
);
}
}
@andreaselia Hi, can you post a sample code with your solution? I will be really grateful
Hopefully the code above is the right one for this.
@andreaselia Yes, it's the right one, it's working, thank you
@andreaselia Yes, it's the right one, it's working, thank you
Good to hear! You're welcome!
Everytime I focus a text field inside a child of the grid the keyboard shows and hide quickly and all widgets are redrawn
I have used the same example provided in the readme with the customscrollview