fixed 33347 fill the gap during performLayout in SliverGrid and SliverFixedExtentList (#33467)
diff --git a/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart b/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart
index 0c5dc4b..221897f 100644
--- a/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart
+++ b/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart
@@ -211,9 +211,9 @@
trailingChildWithLayout = firstChild;
}
- while (targetLastIndex == null || indexOf(trailingChildWithLayout) < targetLastIndex) {
+ for (int index = indexOf(trailingChildWithLayout) + 1; targetLastIndex == null || index <= targetLastIndex; ++index) {
RenderBox child = childAfter(trailingChildWithLayout);
- if (child == null) {
+ if (child == null || indexOf(child) != index) {
child = insertAndLayoutChild(childConstraints, after: trailingChildWithLayout);
if (child == null) {
// We have run out of children.
@@ -225,6 +225,7 @@
trailingChildWithLayout = child;
assert(child != null);
final SliverMultiBoxAdaptorParentData childParentData = child.parentData;
+ assert(childParentData.index == index);
childParentData.layoutOffset = indexToLayoutOffset(itemExtent, childParentData.index);
}
diff --git a/packages/flutter/lib/src/rendering/sliver_grid.dart b/packages/flutter/lib/src/rendering/sliver_grid.dart
index 3d23d56..f5901ef 100644
--- a/packages/flutter/lib/src/rendering/sliver_grid.dart
+++ b/packages/flutter/lib/src/rendering/sliver_grid.dart
@@ -579,7 +579,7 @@
final SliverGridGeometry gridGeometry = layout.getGeometryForChildIndex(index);
final BoxConstraints childConstraints = gridGeometry.getBoxConstraints(constraints);
RenderBox child = childAfter(trailingChildWithLayout);
- if (child == null) {
+ if (child == null || indexOf(child) != index) {
child = insertAndLayoutChild(childConstraints, after: trailingChildWithLayout);
if (child == null) {
// We have run out of children.
diff --git a/packages/flutter/test/widgets/slivers_test.dart b/packages/flutter/test/widgets/slivers_test.dart
index ed5e213..e2c4c93 100644
--- a/packages/flutter/test/widgets/slivers_test.dart
+++ b/packages/flutter/test/widgets/slivers_test.dart
@@ -196,6 +196,73 @@
expect(find.text('BOTTOM'), findsOneWidget);
});
+ testWidgets('SliverGrid Correctly layout children after rearranging', (WidgetTester tester) async {
+ await tester.pumpWidget(const TestSliverGrid(
+ <Widget>[
+ Text('item0', key: Key('0')),
+ Text('item1', key: Key('1')),
+ ]
+ ));
+ await tester.pumpWidget(const TestSliverGrid(
+ <Widget>[
+ Text('item0', key: Key('0')),
+ Text('item3', key: Key('3')),
+ Text('item4', key: Key('4')),
+ Text('item1', key: Key('1')),
+ ]
+ ));
+ expect(find.text('item0'), findsOneWidget);
+ expect(find.text('item3'), findsOneWidget);
+ expect(find.text('item4'), findsOneWidget);
+ expect(find.text('item1'), findsOneWidget);
+
+ final Offset item0Location = tester.getCenter(find.text('item0'));
+ final Offset item3Location = tester.getCenter(find.text('item3'));
+ final Offset item4Location = tester.getCenter(find.text('item4'));
+ final Offset item1Location = tester.getCenter(find.text('item1'));
+
+ expect(isRight(item0Location, item3Location) && sameHorizontal(item0Location, item3Location), true);
+ expect(isBelow(item0Location, item4Location) && sameVertical(item0Location, item4Location), true);
+ expect(isBelow(item0Location, item1Location) && isRight(item0Location, item1Location), true);
+ },
+ );
+
+ testWidgets('SliverFixedExtentList Correctly layout children after rearranging', (WidgetTester tester) async {
+ await tester.pumpWidget(const TestSliverFixedExtentList(
+ <Widget>[
+ Text('item0', key: Key('0')),
+ Text('item2', key: Key('2')),
+ Text('item1', key: Key('1')),
+ ]
+ ));
+ await tester.pumpWidget(const TestSliverFixedExtentList(
+ <Widget>[
+ Text('item0', key: Key('0')),
+ Text('item3', key: Key('3')),
+ Text('item1', key: Key('1')),
+ Text('item4', key: Key('4')),
+ Text('item2', key: Key('2')),
+ ]
+ ));
+ expect(find.text('item0'), findsOneWidget);
+ expect(find.text('item3'), findsOneWidget);
+ expect(find.text('item1'), findsOneWidget);
+ expect(find.text('item4'), findsOneWidget);
+ expect(find.text('item2'), findsOneWidget);
+
+ final Offset item0Location = tester.getCenter(find.text('item0'));
+ final Offset item3Location = tester.getCenter(find.text('item3'));
+ final Offset item1Location = tester.getCenter(find.text('item1'));
+ final Offset item4Location = tester.getCenter(find.text('item4'));
+ final Offset item2Location = tester.getCenter(find.text('item2'));
+
+ expect(isBelow(item0Location, item3Location) && sameVertical(item0Location, item3Location), true);
+ expect(isBelow(item3Location, item1Location) && sameVertical(item3Location, item1Location), true);
+ expect(isBelow(item1Location, item4Location) && sameVertical(item1Location, item4Location), true);
+ expect(isBelow(item4Location, item2Location) && sameVertical(item4Location, item2Location), true);
+ },
+ );
+
testWidgets('Can override ErrorWidget.build', (WidgetTester tester) async {
const Text errorText = Text('error');
final ErrorWidgetBuilder oldBuilder = ErrorWidget.builder;
@@ -212,3 +279,56 @@
ErrorWidget.builder = oldBuilder;
});
}
+
+bool isRight(Offset a, Offset b) => b.dx > a.dx;
+bool isBelow(Offset a, Offset b) => b.dy > a.dy;
+bool sameHorizontal(Offset a, Offset b) => b.dy == a.dy;
+bool sameVertical(Offset a, Offset b) => b.dx == a.dx;
+
+class TestSliverGrid extends StatelessWidget {
+ const TestSliverGrid(this.children);
+
+ final List<Widget> children;
+
+ @override
+ Widget build(BuildContext context) {
+ return Directionality(
+ textDirection: TextDirection.ltr,
+ child: CustomScrollView(
+ slivers: <Widget> [
+ SliverGrid(
+ delegate: SliverChildListDelegate(
+ children,
+ ),
+ gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
+ crossAxisCount: 2,
+ ),
+ ),
+ ],
+ )
+ );
+ }
+}
+
+class TestSliverFixedExtentList extends StatelessWidget {
+ const TestSliverFixedExtentList(this.children);
+
+ final List<Widget> children;
+
+ @override
+ Widget build(BuildContext context) {
+ return Directionality(
+ textDirection: TextDirection.ltr,
+ child: CustomScrollView(
+ slivers: <Widget> [
+ SliverFixedExtentList(
+ itemExtent: 10.0,
+ delegate: SliverChildListDelegate(
+ children,
+ ),
+ ),
+ ],
+ )
+ );
+ }
+}