mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
fix sliverfixedextent with sliverchildbuilderdelegate does not correct calculate max scroll extent (#39142)
This commit is contained in:
parent
f5fc32ff8f
commit
36a7e3f0ef
@ -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(
|
||||
constraints,
|
||||
firstIndex: firstIndex,
|
||||
lastIndex: lastIndex,
|
||||
leadingScrollOffset: leadingScrollOffset,
|
||||
trailingScrollOffset: trailingScrollOffset,
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user