Commit 63828aab authored by Hans Muller's avatar Hans Muller Committed by GitHub

Underflowing LazyBlock should relayout for additional children (#5956)

parent e0f09f5d
...@@ -497,6 +497,9 @@ class _LazyBlockElement extends RenderObjectElement { ...@@ -497,6 +497,9 @@ class _LazyBlockElement extends RenderObjectElement {
/// The largest start offset (exclusive) that can be displayed properly with the items currently represented in [_children]. /// The largest start offset (exclusive) that can be displayed properly with the items currently represented in [_children].
double _startOffsetUpperLimit = 0.0; double _startOffsetUpperLimit = 0.0;
/// True if the children don't fill the viewport.
bool _underflow = false;
int _lastReportedFirstChildLogicalIndex; int _lastReportedFirstChildLogicalIndex;
int _lastReportedLastChildLogicalIndex; int _lastReportedLastChildLogicalIndex;
double _lastReportedFirstChildLogicalOffset; double _lastReportedFirstChildLogicalOffset;
...@@ -597,7 +600,10 @@ class _LazyBlockElement extends RenderObjectElement { ...@@ -597,7 +600,10 @@ class _LazyBlockElement extends RenderObjectElement {
void performRebuild() { void performRebuild() {
IndexedWidgetBuilder builder = widget.delegate.buildItem; IndexedWidgetBuilder builder = widget.delegate.buildItem;
List<Widget> widgets = <Widget>[]; List<Widget> widgets = <Widget>[];
for (int i = 0; i < _children.length; i += 1) { // If the most recent layout didn't fill the viewport but an additional child
// is now available, add it to the widgets list which will force a layout.
int buildChildCount = _underflow ? _children.length + 1 : _children.length;
for (int i = 0; i < buildChildCount; ++i) {
int logicalIndex = _firstChildLogicalIndex + i; int logicalIndex = _firstChildLogicalIndex + i;
Widget childWidget = _callBuilder(builder, logicalIndex); Widget childWidget = _callBuilder(builder, logicalIndex);
if (childWidget == null) if (childWidget == null)
...@@ -701,8 +707,8 @@ class _LazyBlockElement extends RenderObjectElement { ...@@ -701,8 +707,8 @@ class _LazyBlockElement extends RenderObjectElement {
_startOffsetLowerLimit = currentLogicalOffset; _startOffsetLowerLimit = currentLogicalOffset;
} }
// Materialize new children until we fill the viewport (or run out of // Materialize new children until we fill the viewport or run out of
// children to materialize). // children to materialize. If we run out then _underflow is true.
RenderBox child; RenderBox child;
while (currentLogicalOffset < endLogicalOffset) { while (currentLogicalOffset < endLogicalOffset) {
...@@ -737,7 +743,8 @@ class _LazyBlockElement extends RenderObjectElement { ...@@ -737,7 +743,8 @@ class _LazyBlockElement extends RenderObjectElement {
// viewport. The currentLogicalIndex is the index of the first child that // viewport. The currentLogicalIndex is the index of the first child that
// we don't need. // we don't need.
if (currentLogicalOffset < endLogicalOffset) { _underflow = currentLogicalOffset < endLogicalOffset;
if (_underflow) {
// The last element is visible. We can scroll as far as they want, there's // The last element is visible. We can scroll as far as they want, there's
// nothing more to paint. // nothing more to paint.
_startOffsetUpperLimit = double.INFINITY; _startOffsetUpperLimit = double.INFINITY;
......
...@@ -28,4 +28,131 @@ void main() { ...@@ -28,4 +28,131 @@ void main() {
) )
)); ));
}); });
testWidgets('Underflowing LazyBlock should relayout for additional children', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/5950
await tester.pumpWidget(new LazyBlock(
delegate: new LazyBlockChildren(
children: <Widget>[
new SizedBox(height: 100.0, child: new Text('100')),
]
)
));
await tester.pumpWidget(new LazyBlock(
delegate: new LazyBlockChildren(
children: <Widget>[
new SizedBox(height: 100.0, child: new Text('100')),
new SizedBox(height: 200.0, child: new Text('200')),
]
)
));
expect(find.text('200'), findsOneWidget);
});
testWidgets('Underflowing LazyBlock contentExtent should track additional children ', (WidgetTester tester) async {
await tester.pumpWidget(new LazyBlock(
delegate: new LazyBlockChildren(
children: <Widget>[
new SizedBox(height: 100.0, child: new Text('100')),
]
)
));
StatefulElement statefulElement = tester.element(find.byType(Scrollable));
ScrollableState scrollable = statefulElement.state;
OverscrollWhenScrollableBehavior scrollBehavior = scrollable.scrollBehavior;
expect(scrollBehavior.contentExtent, equals(100.0));
await tester.pumpWidget(new LazyBlock(
delegate: new LazyBlockChildren(
children: <Widget>[
new SizedBox(height: 100.0, child: new Text('100')),
new SizedBox(height: 200.0, child: new Text('200')),
]
)
));
expect(scrollBehavior.contentExtent, equals(300.0));
await tester.pumpWidget(new LazyBlock(
delegate: new LazyBlockChildren(
children: <Widget>[
]
)
));
expect(scrollBehavior.contentExtent, equals(0.0));
});
testWidgets('Overflowing LazyBlock should relayout for missing children', (WidgetTester tester) async {
await tester.pumpWidget(new LazyBlock(
delegate: new LazyBlockChildren(
children: <Widget>[
new SizedBox(height: 300.0, child: new Text('300')),
new SizedBox(height: 400.0, child: new Text('400')),
]
)
));
expect(find.text('300'), findsOneWidget);
expect(find.text('400'), findsOneWidget);
await tester.pumpWidget(new LazyBlock(
delegate: new LazyBlockChildren(
children: <Widget>[
new SizedBox(height: 300.0, child: new Text('300')),
]
)
));
expect(find.text('300'), findsOneWidget);
expect(find.text('400'), findsNothing);
await tester.pumpWidget(new LazyBlock(
delegate: new LazyBlockChildren(
children: <Widget>[
]
)
));
expect(find.text('300'), findsNothing);
expect(find.text('400'), findsNothing);
});
testWidgets('Overflowing LazyBlock should not relayout for additional children', (WidgetTester tester) async {
await tester.pumpWidget(new LazyBlock(
delegate: new LazyBlockChildren(
children: <Widget>[
new SizedBox(height: 300.0, child: new Text('300')),
new SizedBox(height: 400.0, child: new Text('400')),
]
)
));
expect(find.text('300'), findsOneWidget);
expect(find.text('400'), findsOneWidget);
await tester.pumpWidget(new LazyBlock(
delegate: new LazyBlockChildren(
children: <Widget>[
new SizedBox(height: 300.0, child: new Text('300')),
new SizedBox(height: 400.0, child: new Text('400')),
new SizedBox(height: 100.0, child: new Text('100')),
]
)
));
expect(find.text('300'), findsOneWidget);
expect(find.text('400'), findsOneWidget);
expect(find.text('100'), findsNothing);
StatefulElement statefulElement = tester.element(find.byType(Scrollable));
ScrollableState scrollable = statefulElement.state;
OverscrollWhenScrollableBehavior scrollBehavior = scrollable.scrollBehavior;
expect(scrollBehavior.contentExtent, equals(700.0));
});
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment