Unverified Commit 36a7e3f0 authored by chunhtai's avatar chunhtai Committed by GitHub

fix sliverfixedextent with sliverchildbuilderdelegate does not correct...

fix sliverfixedextent with sliverchildbuilderdelegate does not correct calculate max scroll extent (#39142)
parent f5fc32ff
......@@ -195,7 +195,24 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
if (firstChild == null) {
if (!addInitialChild(index: firstIndex, layoutOffset: indexToLayoutOffset(itemExtent, firstIndex))) {
// There are either no children, or we are past the end of all our children.
final double max = computeMaxScrollOffset(constraints, itemExtent);
// If it is the later, we will need to find the first available child.
double max;
if (childManager.childCount != null) {
max = computeMaxScrollOffset(constraints, itemExtent);
} else if (firstIndex <= 0) {
max = 0.0;
} else {
// We will have to find it manually.
int possibleFirstIndex = firstIndex - 1;
while (possibleFirstIndex > 0 &&
!addInitialChild(
index: possibleFirstIndex,
layoutOffset: indexToLayoutOffset(itemExtent, possibleFirstIndex)
)
)
possibleFirstIndex -= 1;
max = possibleFirstIndex * itemExtent;
}
geometry = SliverGeometry(
scrollExtent: max,
maxPaintExtent: max,
......@@ -229,12 +246,14 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
trailingChildWithLayout = firstChild;
}
double estimatedMaxScrollOffset = double.infinity;
for (int index = indexOf(trailingChildWithLayout) + 1; targetLastIndex == null || index <= targetLastIndex; ++index) {
RenderBox child = childAfter(trailingChildWithLayout);
if (child == null || indexOf(child) != index) {
child = insertAndLayoutChild(childConstraints, after: trailingChildWithLayout);
if (child == null) {
// We have run out of children.
estimatedMaxScrollOffset = index * itemExtent;
break;
}
} else {
......@@ -256,12 +275,15 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
assert(indexOf(firstChild) == firstIndex);
assert(targetLastIndex == null || lastIndex <= targetLastIndex);
final double estimatedMaxScrollOffset = estimateMaxScrollOffset(
estimatedMaxScrollOffset = math.min(
estimatedMaxScrollOffset,
estimateMaxScrollOffset(
constraints,
firstIndex: firstIndex,
lastIndex: lastIndex,
leadingScrollOffset: leadingScrollOffset,
trailingScrollOffset: trailingScrollOffset,
)
);
final double paintExtent = calculatePaintOffset(
......
......@@ -350,6 +350,70 @@ void main() {
expect(tester.takeException(), 'builder');
ErrorWidget.builder = oldBuilder;
});
testWidgets('SliverFixedExtentList with SliverChildBuilderDelegate auto-correct scroll offset - super fast', (WidgetTester tester) async {
final ScrollController controller = ScrollController(initialScrollOffset: 600);
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: CustomScrollView(
controller: controller,
cacheExtent: 0,
slivers: <Widget>[
SliverFixedExtentList(
itemExtent: 200,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
if (index <= 6) {
return Center(child: Text('Page $index'));
}
return null;
},
),
)
],
),
)
);
await tester.drag(find.text('Page 5'), const Offset(0, -1000));
// Controller will be temporarily over-scrolled.
expect(controller.offset, 1600.0);
await tester.pumpAndSettle();
// It will be corrected after a auto scroll animation.
expect(controller.offset, 800.0);
});
testWidgets('SliverFixedExtentList with SliverChildBuilderDelegate auto-correct scroll offset - reasonable', (WidgetTester tester) async {
final ScrollController controller = ScrollController(initialScrollOffset: 600);
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: CustomScrollView(
controller: controller,
cacheExtent: 0,
slivers: <Widget>[
SliverFixedExtentList(
itemExtent: 200,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
if (index <= 6) {
return Center(child: Text('Page $index'));
}
return null;
},
),
)
],
),
)
);
await tester.drag(find.text('Page 5'), const Offset(0, -210));
// Controller will be temporarily over-scrolled.
expect(controller.offset, 810.0);
await tester.pumpAndSettle();
// It will be corrected after a auto scroll animation.
expect(controller.offset, 800.0);
});
}
bool isRight(Offset a, Offset b) => b.dx > a.dx;
......
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