Unverified Commit 8c5a4111 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Add support for reverse to ReorderableListView (#26203)

parent 830c0dfe
......@@ -41,6 +41,7 @@ class _ListDemoState extends State<ReorderableListDemo> {
PersistentBottomSheetController<void> _bottomSheet;
_ReorderableListType _itemType = _ReorderableListType.threeLine;
bool _reverse = false;
bool _reverseSort = false;
final List<_ListItem> _items = <String>[
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
......@@ -51,7 +52,21 @@ class _ListDemoState extends State<ReorderableListDemo> {
_itemType = type;
});
// Rebuild the bottom sheet to reflect the selected list view.
_bottomSheet?.setState(() { });
_bottomSheet?.setState(() {
// Trigger a rebuild.
});
// Close the bottom sheet to give the user a clear view of the list.
_bottomSheet?.close();
}
void changeReverse(bool newValue) {
setState(() {
_reverse = newValue;
});
// Rebuild the bottom sheet to reflect the selected list view.
_bottomSheet?.setState(() {
// Trigger a rebuild.
});
// Close the bottom sheet to give the user a clear view of the list.
_bottomSheet?.close();
}
......@@ -67,6 +82,12 @@ class _ListDemoState extends State<ReorderableListDemo> {
shrinkWrap: true,
primary: false,
children: <Widget>[
CheckboxListTile(
dense: true,
title: const Text('Reverse'),
value: _reverse,
onChanged: changeReverse,
),
RadioListTile<_ReorderableListType>(
dense: true,
title: const Text('Horizontal Avatars'),
......@@ -189,6 +210,7 @@ class _ListDemoState extends State<ReorderableListDemo> {
child: Text('Header of the list', style: Theme.of(context).textTheme.headline))
: null,
onReorder: _onReorder,
reverse: _reverse,
scrollDirection: _itemType == _ReorderableListType.horizontalAvatar ? Axis.horizontal : Axis.vertical,
padding: const EdgeInsets.symmetric(vertical: 8.0),
children: _items.map<Widget>(buildListTile).toList(),
......
......@@ -59,6 +59,7 @@ class ReorderableListView extends StatefulWidget {
@required this.onReorder,
this.scrollDirection = Axis.vertical,
this.padding,
this.reverse = false,
}): assert(scrollDirection != null),
assert(onReorder != null),
assert(children != null),
......@@ -83,6 +84,20 @@ class ReorderableListView extends StatefulWidget {
/// The amount of space by which to inset the [children].
final EdgeInsets padding;
/// Whether the scroll view scrolls in the reading direction.
///
/// For example, if the reading direction is left-to-right and
/// [scrollDirection] is [Axis.horizontal], then the scroll view scrolls from
/// left to right when [reverse] is false and from right to left when
/// [reverse] is true.
///
/// Similarly, if [scrollDirection] is [Axis.vertical], then the scroll view
/// scrolls from top to bottom when [reverse] is false and from bottom to top
/// when [reverse] is true.
///
/// Defaults to false.
final bool reverse;
/// Called when a list child is dropped into a new position to shuffle the
/// underlying list.
///
......@@ -122,6 +137,7 @@ class _ReorderableListViewState extends State<ReorderableListView> {
scrollDirection: widget.scrollDirection,
onReorder: widget.onReorder,
padding: widget.padding,
reverse: widget.reverse,
);
},
);
......@@ -146,6 +162,7 @@ class _ReorderableListContent extends StatefulWidget {
@required this.scrollDirection,
@required this.padding,
@required this.onReorder,
@required this.reverse,
});
final Widget header;
......@@ -153,6 +170,7 @@ class _ReorderableListContent extends StatefulWidget {
final Axis scrollDirection;
final EdgeInsets padding;
final ReorderCallback onReorder;
final bool reverse;
@override
_ReorderableListContentState createState() => _ReorderableListContentState();
......@@ -544,16 +562,25 @@ class _ReorderableListContentState extends State<_ReorderableListContent> with T
);
break;
}
wrappedChildren.add(_wrap(
finalDropArea,
widget.children.length,
constraints),
);
if (widget.reverse) {
wrappedChildren.insert(0, _wrap(
finalDropArea,
widget.children.length,
constraints),
);
} else {
wrappedChildren.add(_wrap(
finalDropArea,
widget.children.length,
constraints),
);
}
return SingleChildScrollView(
scrollDirection: widget.scrollDirection,
child: _buildContainerForScrollDirection(children: wrappedChildren),
padding: widget.padding,
controller: _scrollController,
reverse: widget.reverse,
);
});
}
......
......@@ -900,6 +900,30 @@ void main() {
});
testWidgets('ReorderableListView can be reversed', (WidgetTester tester) async {
final Widget reorderableListView = ReorderableListView(
children: const <Widget>[
SizedBox(
key: Key('A'),
child: Text('A'),
),
SizedBox(
key: Key('B'),
child: Text('B'),
),
SizedBox(
key: Key('C'),
child: Text('C'),
)
],
reverse: true,
onReorder: (int oldIndex, int newIndex) {},
);
await tester.pumpWidget(MaterialApp(
home: reorderableListView,
));
expect(tester.getCenter(find.text('A')), greaterThan(tester.getCenter(find.text('B'))));
});
// TODO(djshuckerow): figure out how to write a test for scrolling the list.
});
}
......
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