Unverified Commit f79ad055 authored by Darren Austin's avatar Darren Austin Committed by GitHub

Make the ReorderableListView padding scroll with the list. (#80251)

parent 17870d5d
...@@ -487,63 +487,70 @@ class _ReorderableListViewState extends State<ReorderableListView> { ...@@ -487,63 +487,70 @@ class _ReorderableListViewState extends State<ReorderableListView> {
assert(debugCheckHasOverlay(context)); assert(debugCheckHasOverlay(context));
// If there is a header we can't just apply the padding to the list, // If there is a header we can't just apply the padding to the list,
// so we wrap the CustomScrollView in the padding for the top, left and right // so we break it up into padding for the header and padding for the list.
// and only add the padding from the bottom to the sliver list (or the equivalent
// for other axis directions).
final EdgeInsets padding = widget.padding ?? EdgeInsets.zero; final EdgeInsets padding = widget.padding ?? EdgeInsets.zero;
late EdgeInsets outerPadding; late final EdgeInsets headerPadding;
late EdgeInsets listPadding; late final EdgeInsets listPadding;
switch (widget.scrollDirection) {
if (widget.header == null) {
case Axis.horizontal: headerPadding = EdgeInsets.zero;
if (widget.reverse) { listPadding = padding;
outerPadding = EdgeInsets.fromLTRB(0, padding.top, padding.right, padding.bottom); } else {
listPadding = EdgeInsets.fromLTRB(padding.left, 0, 0, 0); switch (widget.scrollDirection) {
} else { case Axis.horizontal:
outerPadding = EdgeInsets.fromLTRB(padding.left, padding.top, 0, padding.bottom); if (widget.reverse) {
listPadding = EdgeInsets.fromLTRB(0, 0, padding.right, 0); // Header on the right
} headerPadding = EdgeInsets.fromLTRB(0, padding.top, padding.right, padding.bottom);
break; listPadding = EdgeInsets.fromLTRB(padding.left, padding.top, 0, padding.bottom);
case Axis.vertical: } else {
if (widget.reverse) { // Header on the left
outerPadding = EdgeInsets.fromLTRB(padding.left, 0, padding.right, padding.bottom); headerPadding = EdgeInsets.fromLTRB(padding.left, padding.top, 0, padding.bottom);
listPadding = EdgeInsets.fromLTRB(0, padding.top, 0, 0); listPadding = EdgeInsets.fromLTRB(0, padding.top, padding.right, padding.bottom);
} else { }
outerPadding = EdgeInsets.fromLTRB(padding.left, padding.top, padding.right, 0); break;
listPadding = EdgeInsets.fromLTRB(0, 0, 0, padding.bottom); case Axis.vertical:
} if (widget.reverse) {
break; // Header on the bottom
headerPadding = EdgeInsets.fromLTRB(padding.left, 0, padding.right, padding.bottom);
listPadding = EdgeInsets.fromLTRB(padding.left, padding.top, padding.right, 0);
} else {
// Header on the top
headerPadding = EdgeInsets.fromLTRB(padding.left, padding.top, padding.right, 0);
listPadding = EdgeInsets.fromLTRB(padding.left, 0, padding.right, padding.bottom);
}
break;
}
} }
return Padding( return CustomScrollView(
padding: outerPadding, scrollDirection: widget.scrollDirection,
child: CustomScrollView( reverse: widget.reverse,
scrollDirection: widget.scrollDirection, controller: widget.scrollController,
reverse: widget.reverse, primary: widget.primary,
controller: widget.scrollController, physics: widget.physics,
primary: widget.primary, shrinkWrap: widget.shrinkWrap,
physics: widget.physics, anchor: widget.anchor,
shrinkWrap: widget.shrinkWrap, cacheExtent: widget.cacheExtent,
anchor: widget.anchor, dragStartBehavior: widget.dragStartBehavior,
cacheExtent: widget.cacheExtent, keyboardDismissBehavior: widget.keyboardDismissBehavior,
dragStartBehavior: widget.dragStartBehavior, restorationId: widget.restorationId,
keyboardDismissBehavior: widget.keyboardDismissBehavior, clipBehavior: widget.clipBehavior,
restorationId: widget.restorationId, slivers: <Widget>[
clipBehavior: widget.clipBehavior, if (widget.header != null)
slivers: <Widget>[
if (widget.header != null)
SliverToBoxAdapter(child: widget.header!),
SliverPadding( SliverPadding(
padding: listPadding, padding: headerPadding,
sliver: SliverReorderableList( sliver: SliverToBoxAdapter(child: widget.header!),
itemBuilder: _itemBuilder,
itemCount: widget.itemCount,
onReorder: widget.onReorder,
proxyDecorator: widget.proxyDecorator ?? _proxyDecorator,
),
), ),
], SliverPadding(
), padding: listPadding,
sliver: SliverReorderableList(
itemBuilder: _itemBuilder,
itemCount: widget.itemCount,
onReorder: widget.onReorder,
proxyDecorator: widget.proxyDecorator ?? _proxyDecorator,
),
),
],
); );
} }
} }
......
...@@ -33,6 +33,8 @@ void main() { ...@@ -33,6 +33,8 @@ void main() {
Widget build({ Widget build({
Widget? header, Widget? header,
Axis scrollDirection = Axis.vertical, Axis scrollDirection = Axis.vertical,
bool reverse = false,
EdgeInsets padding = EdgeInsets.zero,
TextDirection textDirection = TextDirection.ltr, TextDirection textDirection = TextDirection.ltr,
TargetPlatform? platform, TargetPlatform? platform,
}) { }) {
...@@ -48,6 +50,8 @@ void main() { ...@@ -48,6 +50,8 @@ void main() {
children: listItems.map<Widget>(listItemToWidget).toList(), children: listItems.map<Widget>(listItemToWidget).toList(),
scrollDirection: scrollDirection, scrollDirection: scrollDirection,
onReorder: onReorder, onReorder: onReorder,
reverse: reverse,
padding: padding,
), ),
), ),
), ),
...@@ -276,7 +280,7 @@ void main() { ...@@ -276,7 +280,7 @@ void main() {
// first with a gap between the first and third and a drop shadow on // first with a gap between the first and third and a drop shadow on
// the dragged item. // the dragged item.
await expectLater( await expectLater(
find.byType(ReorderableListView), find.byType(Overlay).last,
matchesGoldenFile('reorderable_list_test.vertical.drop_area.png'), matchesGoldenFile('reorderable_list_test.vertical.drop_area.png'),
); );
debugDisableShadows = true; debugDisableShadows = true;
...@@ -888,7 +892,7 @@ void main() { ...@@ -888,7 +892,7 @@ void main() {
// first with a gap between the first and third and a drop shadow on // first with a gap between the first and third and a drop shadow on
// the dragged item. // the dragged item.
await expectLater( await expectLater(
find.byType(ReorderableListView), find.byType(Overlay).last,
matchesGoldenFile('reorderable_list_test.horizontal.drop_area.png'), matchesGoldenFile('reorderable_list_test.horizontal.drop_area.png'),
); );
debugDisableShadows = true; debugDisableShadows = true;
...@@ -1238,6 +1242,53 @@ void main() { ...@@ -1238,6 +1242,53 @@ void main() {
expect(itemsCreated, <int>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}); expect(itemsCreated, <int>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17});
}); });
group('Padding', () {
testWidgets('Padding with no header', (WidgetTester tester) async {
const EdgeInsets padding = EdgeInsets.fromLTRB(10, 20, 30, 40);
// Vertical
await tester.pumpWidget(build(padding: padding));
expect(tester.getRect(find.byKey(const Key('Item 1'))), const Rect.fromLTRB(10, 20, 770, 68));
expect(tester.getRect(find.byKey(const Key('Item 4'))), const Rect.fromLTRB(10, 164, 770, 212));
// Horizontal
await tester.pumpWidget(build(padding: padding, scrollDirection: Axis.horizontal));
expect(tester.getRect(find.byKey(const Key('Item 1'))), const Rect.fromLTRB(10, 20, 58, 560));
expect(tester.getRect(find.byKey(const Key('Item 4'))), const Rect.fromLTRB(154, 20, 202, 560));
});
testWidgets('Padding with header', (WidgetTester tester) async {
const EdgeInsets padding = EdgeInsets.fromLTRB(10, 20, 30, 40);
const Key headerKey = Key('Header');
const Widget verticalHeader = SizedBox(key: headerKey, height: 10);
const Widget horizontalHeader = SizedBox(key: headerKey, width: 10);
// Vertical
await tester.pumpWidget(build(padding: padding, header: verticalHeader));
expect(tester.getRect(find.byKey(headerKey)), const Rect.fromLTRB(10, 20, 770, 30));
expect(tester.getRect(find.byKey(const Key('Item 1'))), const Rect.fromLTRB(10, 30, 770, 78));
expect(tester.getRect(find.byKey(const Key('Item 4'))), const Rect.fromLTRB(10, 174, 770, 222));
// Vertical, reversed
await tester.pumpWidget(build(padding: padding, header: verticalHeader, reverse: true));
expect(tester.getRect(find.byKey(headerKey)), const Rect.fromLTRB(10, 550, 770, 560));
expect(tester.getRect(find.byKey(const Key('Item 1'))), const Rect.fromLTRB(10, 502, 770, 550));
expect(tester.getRect(find.byKey(const Key('Item 4'))), const Rect.fromLTRB(10, 358, 770, 406));
// Horizontal
await tester.pumpWidget(build(padding: padding, header: horizontalHeader, scrollDirection: Axis.horizontal));
expect(tester.getRect(find.byKey(headerKey)), const Rect.fromLTRB(10, 20, 20, 560));
expect(tester.getRect(find.byKey(const Key('Item 1'))), const Rect.fromLTRB(20, 20, 68, 560));
expect(tester.getRect(find.byKey(const Key('Item 4'))), const Rect.fromLTRB(164, 20, 212, 560));
// Horizontal, reversed
await tester.pumpWidget(build(padding: padding, header: horizontalHeader, scrollDirection: Axis.horizontal, reverse: true));
expect(tester.getRect(find.byKey(headerKey)), const Rect.fromLTRB(760, 20, 770, 560));
expect(tester.getRect(find.byKey(const Key('Item 1'))), const Rect.fromLTRB(712, 20, 760, 560));
expect(tester.getRect(find.byKey(const Key('Item 4'))), const Rect.fromLTRB(568, 20, 616, 560));
});
});
testWidgets('ReorderableListView can be reversed', (WidgetTester tester) async { testWidgets('ReorderableListView can be reversed', (WidgetTester tester) async {
final Widget reorderableListView = ReorderableListView( final Widget reorderableListView = ReorderableListView(
children: const <Widget>[ children: const <Widget>[
......
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