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 (firstChild == null) {
|
||||||
if (!addInitialChild(index: firstIndex, layoutOffset: indexToLayoutOffset(itemExtent, firstIndex))) {
|
if (!addInitialChild(index: firstIndex, layoutOffset: indexToLayoutOffset(itemExtent, firstIndex))) {
|
||||||
// There are either no children, or we are past the end of all our children.
|
// 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(
|
geometry = SliverGeometry(
|
||||||
scrollExtent: max,
|
scrollExtent: max,
|
||||||
maxPaintExtent: max,
|
maxPaintExtent: max,
|
||||||
@ -229,12 +246,14 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
|
|||||||
trailingChildWithLayout = firstChild;
|
trailingChildWithLayout = firstChild;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double estimatedMaxScrollOffset = double.infinity;
|
||||||
for (int index = indexOf(trailingChildWithLayout) + 1; targetLastIndex == null || index <= targetLastIndex; ++index) {
|
for (int index = indexOf(trailingChildWithLayout) + 1; targetLastIndex == null || index <= targetLastIndex; ++index) {
|
||||||
RenderBox child = childAfter(trailingChildWithLayout);
|
RenderBox child = childAfter(trailingChildWithLayout);
|
||||||
if (child == null || indexOf(child) != index) {
|
if (child == null || indexOf(child) != index) {
|
||||||
child = insertAndLayoutChild(childConstraints, after: trailingChildWithLayout);
|
child = insertAndLayoutChild(childConstraints, after: trailingChildWithLayout);
|
||||||
if (child == null) {
|
if (child == null) {
|
||||||
// We have run out of children.
|
// We have run out of children.
|
||||||
|
estimatedMaxScrollOffset = index * itemExtent;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -256,12 +275,15 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
|
|||||||
assert(indexOf(firstChild) == firstIndex);
|
assert(indexOf(firstChild) == firstIndex);
|
||||||
assert(targetLastIndex == null || lastIndex <= targetLastIndex);
|
assert(targetLastIndex == null || lastIndex <= targetLastIndex);
|
||||||
|
|
||||||
final double estimatedMaxScrollOffset = estimateMaxScrollOffset(
|
estimatedMaxScrollOffset = math.min(
|
||||||
constraints,
|
estimatedMaxScrollOffset,
|
||||||
firstIndex: firstIndex,
|
estimateMaxScrollOffset(
|
||||||
lastIndex: lastIndex,
|
constraints,
|
||||||
leadingScrollOffset: leadingScrollOffset,
|
firstIndex: firstIndex,
|
||||||
trailingScrollOffset: trailingScrollOffset,
|
lastIndex: lastIndex,
|
||||||
|
leadingScrollOffset: leadingScrollOffset,
|
||||||
|
trailingScrollOffset: trailingScrollOffset,
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
final double paintExtent = calculatePaintOffset(
|
final double paintExtent = calculatePaintOffset(
|
||||||
|
@ -350,6 +350,70 @@ void main() {
|
|||||||
expect(tester.takeException(), 'builder');
|
expect(tester.takeException(), 'builder');
|
||||||
ErrorWidget.builder = oldBuilder;
|
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;
|
bool isRight(Offset a, Offset b) => b.dx > a.dx;
|
||||||
|
Loading…
Reference in New Issue
Block a user