Adding itemExtent
to ReorderableList
and ReorderableListView
(#81372)
This commit is contained in:
parent
d97f41caed
commit
b6d13a6122
@ -76,6 +76,7 @@ class ReorderableListView extends StatefulWidget {
|
||||
Key? key,
|
||||
required List<Widget> children,
|
||||
required this.onReorder,
|
||||
this.itemExtent,
|
||||
this.proxyDecorator,
|
||||
this.buildDefaultDragHandles = true,
|
||||
this.padding,
|
||||
@ -168,6 +169,7 @@ class ReorderableListView extends StatefulWidget {
|
||||
required this.itemBuilder,
|
||||
required this.itemCount,
|
||||
required this.onReorder,
|
||||
this.itemExtent,
|
||||
this.proxyDecorator,
|
||||
this.buildDefaultDragHandles = true,
|
||||
this.padding,
|
||||
@ -323,6 +325,9 @@ class ReorderableListView extends StatefulWidget {
|
||||
/// Defaults to [Clip.hardEdge].
|
||||
final Clip clipBehavior;
|
||||
|
||||
/// {@macro flutter.widgets.list_view.itemExtent}
|
||||
final double? itemExtent;
|
||||
|
||||
@override
|
||||
_ReorderableListViewState createState() => _ReorderableListViewState();
|
||||
}
|
||||
@ -545,6 +550,7 @@ class _ReorderableListViewState extends State<ReorderableListView> {
|
||||
padding: listPadding,
|
||||
sliver: SliverReorderableList(
|
||||
itemBuilder: _itemBuilder,
|
||||
itemExtent: widget.itemExtent,
|
||||
itemCount: widget.itemCount,
|
||||
onReorder: widget.onReorder,
|
||||
proxyDecorator: widget.proxyDecorator ?? _proxyDecorator,
|
||||
|
@ -112,6 +112,7 @@ class ReorderableList extends StatefulWidget {
|
||||
required this.itemBuilder,
|
||||
required this.itemCount,
|
||||
required this.onReorder,
|
||||
this.itemExtent,
|
||||
this.proxyDecorator,
|
||||
this.padding,
|
||||
this.scrollDirection = Axis.vertical,
|
||||
@ -211,6 +212,9 @@ class ReorderableList extends StatefulWidget {
|
||||
/// Defaults to [Clip.hardEdge].
|
||||
final Clip clipBehavior;
|
||||
|
||||
/// {@macro flutter.widgets.list_view.itemExtent}
|
||||
final double? itemExtent;
|
||||
|
||||
/// The state from the closest instance of this class that encloses the given
|
||||
/// context.
|
||||
///
|
||||
@ -337,6 +341,7 @@ class ReorderableListState extends State<ReorderableList> {
|
||||
padding: widget.padding ?? EdgeInsets.zero,
|
||||
sliver: SliverReorderableList(
|
||||
key: _sliverReorderableListKey,
|
||||
itemExtent: widget.itemExtent,
|
||||
itemBuilder: widget.itemBuilder,
|
||||
itemCount: widget.itemCount,
|
||||
onReorder: widget.onReorder,
|
||||
@ -380,6 +385,7 @@ class SliverReorderableList extends StatefulWidget {
|
||||
required this.itemBuilder,
|
||||
required this.itemCount,
|
||||
required this.onReorder,
|
||||
this.itemExtent,
|
||||
this.proxyDecorator,
|
||||
}) : assert(itemCount >= 0),
|
||||
super(key: key);
|
||||
@ -396,6 +402,9 @@ class SliverReorderableList extends StatefulWidget {
|
||||
/// {@macro flutter.widgets.reorderable_list.proxyDecorator}
|
||||
final ReorderItemProxyDecorator? proxyDecorator;
|
||||
|
||||
/// {@macro flutter.widgets.list_view.itemExtent}
|
||||
final double? itemExtent;
|
||||
|
||||
@override
|
||||
SliverReorderableListState createState() => SliverReorderableListState();
|
||||
|
||||
@ -825,15 +834,19 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasOverlay(context));
|
||||
return SliverList(
|
||||
final SliverChildBuilderDelegate childrenDelegate = SliverChildBuilderDelegate(
|
||||
_itemBuilder,
|
||||
// When dragging, the dragged item is still in the list but has been replaced
|
||||
// by a zero height SizedBox, so that the gap can move around. To make the
|
||||
// list extent stable we add a dummy entry to the end.
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
_itemBuilder,
|
||||
childCount: widget.itemCount + (_dragInfo != null ? 1 : 0),
|
||||
),
|
||||
childCount: widget.itemCount + (_dragInfo != null ? 1 : 0),
|
||||
);
|
||||
return widget.itemExtent != null
|
||||
? SliverFixedExtentList(
|
||||
itemExtent: widget.itemExtent!,
|
||||
delegate: childrenDelegate,
|
||||
)
|
||||
: SliverList(delegate: childrenDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1476,6 +1476,7 @@ class ListView extends BoxScrollView {
|
||||
clipBehavior: clipBehavior,
|
||||
);
|
||||
|
||||
/// {@template flutter.widgets.list_view.itemExtent}
|
||||
/// If non-null, forces the children to have the given extent in the scroll
|
||||
/// direction.
|
||||
///
|
||||
@ -1489,6 +1490,7 @@ class ListView extends BoxScrollView {
|
||||
/// * [SliverFixedExtentList], the sliver used internally when this property
|
||||
/// is provided. It constrains its box children to have a specific given
|
||||
/// extent along the main axis.
|
||||
/// {@endtemplate}
|
||||
/// * The [prototypeItem] property, which allows forcing the children's
|
||||
/// extent to be the same as the given widget.
|
||||
final double? itemExtent;
|
||||
|
@ -1505,6 +1505,51 @@ void main() {
|
||||
expect(exception.toString(), contains('No Overlay widget found'));
|
||||
expect(exception.toString(), contains('ReorderableListView widgets require an Overlay widget ancestor'));
|
||||
});
|
||||
|
||||
testWidgets('if itemExtent is non-null, children have same extent in the scroll direction', (WidgetTester tester) async {
|
||||
final List<int> numbers = <int>[0,1,2];
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return ReorderableListView.builder(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return SizedBox(
|
||||
key: ValueKey<int>(numbers[index]),
|
||||
// children with different heights
|
||||
height: 20 + numbers[index] * 10,
|
||||
child: ReorderableDragStartListener(
|
||||
index: index,
|
||||
child: Text(numbers[index].toString()),
|
||||
)
|
||||
);
|
||||
},
|
||||
itemCount: numbers.length,
|
||||
itemExtent: 30,
|
||||
onReorder: (int fromIndex, int toIndex) {
|
||||
if (fromIndex < toIndex) {
|
||||
toIndex--;
|
||||
}
|
||||
final int value = numbers.removeAt(fromIndex);
|
||||
numbers.insert(toIndex, value);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
final double item0Height = tester.getSize(find.text('0').hitTestable()).height;
|
||||
final double item1Height = tester.getSize(find.text('1').hitTestable()).height;
|
||||
final double item2Height = tester.getSize(find.text('2').hitTestable()).height;
|
||||
|
||||
expect(item0Height, 30.0);
|
||||
expect(item1Height, 30.0);
|
||||
expect(item2Height, 30.0);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> longPressDrag(WidgetTester tester, Offset start, Offset end) async {
|
||||
|
@ -267,6 +267,51 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
expect(getItemFadeTransition(), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('if itemExtent is non-null, children have same extent in the scroll direction', (WidgetTester tester) async {
|
||||
final List<int> numbers = <int>[0,1,2];
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return ReorderableList(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return SizedBox(
|
||||
key: ValueKey<int>(numbers[index]),
|
||||
// children with different heights
|
||||
height: 20 + numbers[index] * 10,
|
||||
child: ReorderableDragStartListener(
|
||||
index: index,
|
||||
child: Text(numbers[index].toString()),
|
||||
)
|
||||
);
|
||||
},
|
||||
itemCount: numbers.length,
|
||||
itemExtent: 30,
|
||||
onReorder: (int fromIndex, int toIndex) {
|
||||
if (fromIndex < toIndex) {
|
||||
toIndex--;
|
||||
}
|
||||
final int value = numbers.removeAt(fromIndex);
|
||||
numbers.insert(toIndex, value);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
final double item0Height = tester.getSize(find.text('0').hitTestable()).height;
|
||||
final double item1Height = tester.getSize(find.text('1').hitTestable()).height;
|
||||
final double item2Height = tester.getSize(find.text('2').hitTestable()).height;
|
||||
|
||||
expect(item0Height, 30.0);
|
||||
expect(item1Height, 30.0);
|
||||
expect(item2Height, 30.0);
|
||||
});
|
||||
}
|
||||
|
||||
class TestList extends StatefulWidget {
|
||||
|
@ -1334,4 +1334,42 @@ void main() {
|
||||
equals(const Rect.fromLTRB(0.0, 0.0, 800.0, 50.0)),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('if itemExtent is non-null, children have same extent in the scroll direction', (WidgetTester tester) async {
|
||||
final List<int> numbers = <int>[0,1,2];
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return ListView.builder(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return SizedBox(
|
||||
key: ValueKey<int>(numbers[index]),
|
||||
// children with different heights
|
||||
height: 20 + numbers[index] * 10,
|
||||
child: ReorderableDragStartListener(
|
||||
index: index,
|
||||
child: Text(numbers[index].toString()),
|
||||
)
|
||||
);
|
||||
},
|
||||
itemCount: numbers.length,
|
||||
itemExtent: 30,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
final double item0Height = tester.getSize(find.text('0').hitTestable()).height;
|
||||
final double item1Height = tester.getSize(find.text('1').hitTestable()).height;
|
||||
final double item2Height = tester.getSize(find.text('2').hitTestable()).height;
|
||||
|
||||
expect(item0Height, 30.0);
|
||||
expect(item1Height, 30.0);
|
||||
expect(item2Height, 30.0);
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user