mirror of
https://github.com/flutter/flutter
synced 2024-08-25 02:46:31 +00:00
Change ItemExtentBuilder
's return value nullable (#142428)
Fixes https://github.com/flutter/flutter/issues/138912 Change `ItemExtentBuilder`'s return value nullable, it should return null if asked to build an item extent with a greater index than exists.
This commit is contained in:
parent
bb1271d483
commit
6707f5efbe
|
@ -18,8 +18,11 @@ import 'viewport_offset.dart';
|
|||
|
||||
/// Called to get the item extent by the index of item.
|
||||
///
|
||||
/// Should return null if asked to build an item extent with a greater index than
|
||||
/// exists.
|
||||
///
|
||||
/// Used by [ListView.itemExtentBuilder] and [SliverVariedExtentList.itemExtentBuilder].
|
||||
typedef ItemExtentBuilder = double Function(int index, SliverLayoutDimensions dimensions);
|
||||
typedef ItemExtentBuilder = double? Function(int index, SliverLayoutDimensions dimensions);
|
||||
|
||||
/// Relates the dimensions of the [RenderSliver] during layout.
|
||||
///
|
||||
|
|
|
@ -67,8 +67,17 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
|
|||
return itemExtent * index;
|
||||
} else {
|
||||
double offset = 0.0;
|
||||
double? itemExtent;
|
||||
for (int i = 0; i < index; i++) {
|
||||
offset += itemExtentBuilder!(i, _currentLayoutDimensions);
|
||||
final int? childCount = childManager.estimatedChildCount;
|
||||
if (childCount != null && i > childCount - 1) {
|
||||
break;
|
||||
}
|
||||
itemExtent = itemExtentBuilder!(i, _currentLayoutDimensions);
|
||||
if (itemExtent == null) {
|
||||
break;
|
||||
}
|
||||
offset += itemExtent;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
@ -179,8 +188,13 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
|
|||
return childManager.childCount * itemExtent;
|
||||
} else {
|
||||
double offset = 0.0;
|
||||
double? itemExtent;
|
||||
for (int i = 0; i < childManager.childCount; i++) {
|
||||
offset += itemExtentBuilder!(i, _currentLayoutDimensions);
|
||||
itemExtent = itemExtentBuilder!(i, _currentLayoutDimensions);
|
||||
if (itemExtent == null) {
|
||||
break;
|
||||
}
|
||||
offset += itemExtent;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
@ -212,8 +226,17 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
|
|||
}
|
||||
double position = 0.0;
|
||||
int index = 0;
|
||||
double? itemExtent;
|
||||
while (position < scrollOffset) {
|
||||
position += callback(index, _currentLayoutDimensions);
|
||||
final int? childCount = childManager.estimatedChildCount;
|
||||
if (childCount != null && index > childCount - 1) {
|
||||
break;
|
||||
}
|
||||
itemExtent = callback(index, _currentLayoutDimensions);
|
||||
if (itemExtent == null) {
|
||||
break;
|
||||
}
|
||||
position += itemExtent;
|
||||
++index;
|
||||
}
|
||||
return index - 1;
|
||||
|
@ -224,7 +247,7 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
|
|||
if (itemExtentBuilder == null) {
|
||||
extent = itemExtent!;
|
||||
} else {
|
||||
extent = itemExtentBuilder!(index, _currentLayoutDimensions);
|
||||
extent = itemExtentBuilder!(index, _currentLayoutDimensions)!;
|
||||
}
|
||||
return constraints.asBoxConstraints(
|
||||
minExtent: extent,
|
||||
|
|
|
@ -79,6 +79,17 @@ abstract class RenderSliverBoxChildManager {
|
|||
/// list).
|
||||
int get childCount;
|
||||
|
||||
/// The best available estimate of [childCount], or null if no estimate is available.
|
||||
///
|
||||
/// This differs from [childCount] in that [childCount] never returns null (and must
|
||||
/// not be accessed if the child count is not yet available, meaning the [createChild]
|
||||
/// method has not been provided an index that does not create a child).
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SliverChildDelegate.estimatedChildCount], to which this getter defers.
|
||||
int? get estimatedChildCount => null;
|
||||
|
||||
/// Called during [RenderSliverMultiBoxAdaptor.adoptChild] or
|
||||
/// [RenderSliverMultiBoxAdaptor.move].
|
||||
///
|
||||
|
|
|
@ -1506,6 +1506,9 @@ class ListView extends BoxScrollView {
|
|||
/// This will be called multiple times during the layout phase of a frame to find
|
||||
/// the items that should be loaded by the lazy loading process.
|
||||
///
|
||||
/// Should return null if asked to build an item extent with a greater index than
|
||||
/// exists.
|
||||
///
|
||||
/// Unlike [itemExtent] or [prototypeItem], this allows children to have
|
||||
/// different extents.
|
||||
///
|
||||
|
|
|
@ -937,15 +937,7 @@ class SliverMultiBoxAdaptorElement extends RenderObjectElement implements Render
|
|||
);
|
||||
}
|
||||
|
||||
/// The best available estimate of [childCount], or null if no estimate is available.
|
||||
///
|
||||
/// This differs from [childCount] in that [childCount] never returns null (and must
|
||||
/// not be accessed if the child count is not yet available, meaning the [createChild]
|
||||
/// method has not been provided an index that does not create a child).
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SliverChildDelegate.estimatedChildCount], to which this getter defers.
|
||||
@override
|
||||
int? get estimatedChildCount => (widget as SliverMultiBoxAdaptorWidget).delegate.estimatedChildCount;
|
||||
|
||||
@override
|
||||
|
|
|
@ -98,6 +98,9 @@ class SliverVariedExtentList extends SliverMultiBoxAdaptorWidget {
|
|||
));
|
||||
|
||||
/// The children extent builder.
|
||||
///
|
||||
/// Should return null if asked to build an item extent with a greater index than
|
||||
/// exists.
|
||||
final ItemExtentBuilder itemExtentBuilder;
|
||||
|
||||
@override
|
||||
|
|
|
@ -780,6 +780,37 @@ void main() {
|
|||
expect(renderObject.clipBehavior, equals(Clip.antiAlias));
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/pull/138912
|
||||
testWidgets('itemExtentBuilder should respect item count', (WidgetTester tester) async {
|
||||
final ScrollController controller = ScrollController();
|
||||
addTearDown(controller.dispose);
|
||||
final List<double> numbers = <double>[
|
||||
10, 20, 30, 40, 50,
|
||||
];
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: ListView.builder(
|
||||
controller: controller,
|
||||
itemCount: numbers.length,
|
||||
itemExtentBuilder: (int index, SliverLayoutDimensions dimensions) {
|
||||
return numbers[index];
|
||||
},
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return SizedBox(
|
||||
height: numbers[index],
|
||||
child: Text('Item $index'),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text('Item 0'), findsOneWidget);
|
||||
expect(find.text('Item 4'), findsOneWidget);
|
||||
expect(find.text('Item 5'), findsNothing);
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/pull/131393
|
||||
testWidgets('itemExtentBuilder test', (WidgetTester tester) async {
|
||||
final ScrollController controller = ScrollController();
|
||||
|
|
Loading…
Reference in a new issue