Commit 311e77ab authored by Adam Barth's avatar Adam Barth Committed by GitHub

Fix main stocks screen (#8008)

We weren't triggering a relayout when the number of children changed.

Fixes #8001
parent 2ec6b31a
......@@ -21,6 +21,7 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
@override
void performLayout() {
assert(childManager.debugAssertChildListLocked());
childManager.setDidUnderflow(false);
final double itemExtent = this.itemExtent;
double indexToScrollOffset(int index) => itemExtent * index;
......
......@@ -445,6 +445,8 @@ class RenderSliverGrid extends RenderSliverMultiBoxAdaptor {
@override
void performLayout() {
assert(childManager.debugAssertChildListLocked());
childManager.setDidUnderflow(false);
final double scrollOffset = constraints.scrollOffset;
assert(scrollOffset >= 0.0);
final double remainingPaintExtent = constraints.remainingPaintExtent;
......
......@@ -17,6 +17,8 @@ class RenderSliverList extends RenderSliverMultiBoxAdaptor {
@override
void performLayout() {
assert(childManager.debugAssertChildListLocked());
childManager.setDidUnderflow(false);
double scrollOffset = constraints.scrollOffset;
assert(scrollOffset >= 0.0);
double remainingPaintExtent = constraints.remainingPaintExtent;
......
......@@ -75,6 +75,8 @@ abstract class RenderSliverBoxChildManager {
/// the child list after this function returns.
void didAdoptChild(RenderBox child);
void setDidUnderflow(bool value);
/// In debug mode, asserts that this manager is not expecting any
/// modifications to the [RenderSliverMultiBoxAdaptor]'s child list.
///
......@@ -174,6 +176,7 @@ abstract class RenderSliverMultiBoxAdaptor extends RenderSliver
firstChildParentData.layoutOffset = scrollOffset;
result = true;
} else {
childManager.setDidUnderflow(true);
result = false;
}
});
......@@ -206,6 +209,7 @@ abstract class RenderSliverMultiBoxAdaptor extends RenderSliver
firstChild.layout(childConstraints, parentUsesSize: parentUsesSize);
return firstChild;
}
childManager.setDidUnderflow(true);
return null;
}
......@@ -238,6 +242,7 @@ abstract class RenderSliverMultiBoxAdaptor extends RenderSliver
child.layout(childConstraints, parentUsesSize: parentUsesSize);
return child;
}
childManager.setDidUnderflow(true);
return null;
}
......
......@@ -108,6 +108,8 @@ class _GlowingOverscrollIndicatorState extends State<GlowingOverscrollIndicator>
}
bool _handleScrollNotification(ScrollNotification2 notification) {
if (notification.depth != 0)
return false;
if (notification is OverscrollNotification) {
_GlowController controller;
if (notification.overscroll < 0.0) {
......
......@@ -258,7 +258,7 @@ class SliverMultiBoxAdaptorElement extends RenderObjectElement implements Render
performRebuild();
}
Map<int, Element> _childElements = new SplayTreeMap<int, Element>();
SplayTreeMap<int, Element> _childElements = new SplayTreeMap<int, Element>();
Map<int, Widget> _childWidgets = new HashMap<int, Widget>();
RenderBox _currentBeforeChild;
......@@ -269,14 +269,18 @@ class SliverMultiBoxAdaptorElement extends RenderObjectElement implements Render
_currentBeforeChild = null;
assert(_currentlyUpdatingChildIndex == null);
try {
// The "toList()" below is to get a copy of the array so that we can
// mutate _childElements within the loop. Basically we just update all the
// same indexes as we had before. If any of them mutate the tree, then
// this will also trigger a layout and so forth. (We won't call the
// delegate's build function multiple times, though, because we cache the
// delegate's results until the next time we need to rebuild the whole
// block widget.)
for (int index in _childElements.keys.toList()) {
int firstIndex = _childElements.firstKey();
int lastIndex = _childElements.lastKey();
if (_childElements.isEmpty) {
firstIndex = 0;
lastIndex = 0;
} else if (_didUnderflow) {
lastIndex += 1;
}
// We won't call the delegate's build function multiple times, because we
// cache the delegate's results until the next time we need to rebuild the
// whole widget.
for (int index = firstIndex; index <= lastIndex; ++index) {
_currentlyUpdatingChildIndex = index;
Element newChild = updateChild(_childElements[index], _build(index), index);
if (newChild != null) {
......@@ -397,6 +401,13 @@ class SliverMultiBoxAdaptorElement extends RenderObjectElement implements Render
childParentData.index = _currentlyUpdatingChildIndex;
}
bool _didUnderflow = false;
@override
void setDidUnderflow(bool value) {
_didUnderflow = value;
}
@override
void insertChildRenderObject(@checked RenderObject child, int slot) {
assert(slot != null);
......
......@@ -59,6 +59,9 @@ class TestRenderSliverBoxChildManager extends RenderSliverBoxChildManager {
final SliverMultiBoxAdaptorParentData childParentData = child.parentData;
childParentData.index = _currentlyUpdatingChildIndex;
}
@override
void setDidUnderflow(bool value) { }
}
void main() {
......
......@@ -89,4 +89,55 @@ void main() {
expect(log, equals(<int>[4, 5, 6, 7]));
log.clear();
});
testWidgets('ListView can build out of underflow', (WidgetTester tester) async {
await tester.pumpWidget(
new ListView(
itemExtent: 100.0,
),
);
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsNothing);
expect(find.text('2'), findsNothing);
expect(find.text('3'), findsNothing);
expect(find.text('4'), findsNothing);
expect(find.text('5'), findsNothing);
await tester.pumpWidget(
new ListView(
itemExtent: 100.0,
children: new List<Widget>.generate(2, (int i) {
return new Container(
child: new Text('$i'),
);
}),
),
);
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsOneWidget);
expect(find.text('2'), findsNothing);
expect(find.text('3'), findsNothing);
expect(find.text('4'), findsNothing);
expect(find.text('5'), findsNothing);
await tester.pumpWidget(
new ListView(
itemExtent: 100.0,
children: new List<Widget>.generate(5, (int i) {
return new Container(
child: new Text('$i'),
);
}),
),
);
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsOneWidget);
expect(find.text('2'), findsOneWidget);
expect(find.text('3'), findsOneWidget);
expect(find.text('4'), findsOneWidget);
expect(find.text('5'), findsNothing);
});
}
......@@ -197,6 +197,29 @@ void main() {
expect(painter, doesNotOverscroll);
});
testWidgets('Nested overscrolls do not throw exceptions', (WidgetTester tester) async {
await tester.pumpWidget(
new PageView(
children: <Widget>[
new ListView(
children: <Widget>[
new Container(
width: 2000.0,
height: 2000.0,
decoration: new BoxDecoration(
backgroundColor: const Color(0xFF00FF00),
),
),
],
),
],
),
);
await tester.scrollAt(const Point(100.0, 100.0), const Offset(0.0, 2000.0));
await tester.pumpUntilNoTransientCallbacks();
});
testWidgets('Changing settings', (WidgetTester tester) async {
RenderObject painter;
......
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