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> { ...@@ -41,6 +41,7 @@ class _ListDemoState extends State<ReorderableListDemo> {
PersistentBottomSheetController<void> _bottomSheet; PersistentBottomSheetController<void> _bottomSheet;
_ReorderableListType _itemType = _ReorderableListType.threeLine; _ReorderableListType _itemType = _ReorderableListType.threeLine;
bool _reverse = false;
bool _reverseSort = false; bool _reverseSort = false;
final List<_ListItem> _items = <String>[ final List<_ListItem> _items = <String>[
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
...@@ -51,7 +52,21 @@ class _ListDemoState extends State<ReorderableListDemo> { ...@@ -51,7 +52,21 @@ class _ListDemoState extends State<ReorderableListDemo> {
_itemType = type; _itemType = type;
}); });
// Rebuild the bottom sheet to reflect the selected list view. // 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. // Close the bottom sheet to give the user a clear view of the list.
_bottomSheet?.close(); _bottomSheet?.close();
} }
...@@ -67,6 +82,12 @@ class _ListDemoState extends State<ReorderableListDemo> { ...@@ -67,6 +82,12 @@ class _ListDemoState extends State<ReorderableListDemo> {
shrinkWrap: true, shrinkWrap: true,
primary: false, primary: false,
children: <Widget>[ children: <Widget>[
CheckboxListTile(
dense: true,
title: const Text('Reverse'),
value: _reverse,
onChanged: changeReverse,
),
RadioListTile<_ReorderableListType>( RadioListTile<_ReorderableListType>(
dense: true, dense: true,
title: const Text('Horizontal Avatars'), title: const Text('Horizontal Avatars'),
...@@ -189,6 +210,7 @@ class _ListDemoState extends State<ReorderableListDemo> { ...@@ -189,6 +210,7 @@ class _ListDemoState extends State<ReorderableListDemo> {
child: Text('Header of the list', style: Theme.of(context).textTheme.headline)) child: Text('Header of the list', style: Theme.of(context).textTheme.headline))
: null, : null,
onReorder: _onReorder, onReorder: _onReorder,
reverse: _reverse,
scrollDirection: _itemType == _ReorderableListType.horizontalAvatar ? Axis.horizontal : Axis.vertical, scrollDirection: _itemType == _ReorderableListType.horizontalAvatar ? Axis.horizontal : Axis.vertical,
padding: const EdgeInsets.symmetric(vertical: 8.0), padding: const EdgeInsets.symmetric(vertical: 8.0),
children: _items.map<Widget>(buildListTile).toList(), children: _items.map<Widget>(buildListTile).toList(),
......
...@@ -59,6 +59,7 @@ class ReorderableListView extends StatefulWidget { ...@@ -59,6 +59,7 @@ class ReorderableListView extends StatefulWidget {
@required this.onReorder, @required this.onReorder,
this.scrollDirection = Axis.vertical, this.scrollDirection = Axis.vertical,
this.padding, this.padding,
this.reverse = false,
}): assert(scrollDirection != null), }): assert(scrollDirection != null),
assert(onReorder != null), assert(onReorder != null),
assert(children != null), assert(children != null),
...@@ -83,6 +84,20 @@ class ReorderableListView extends StatefulWidget { ...@@ -83,6 +84,20 @@ class ReorderableListView extends StatefulWidget {
/// The amount of space by which to inset the [children]. /// The amount of space by which to inset the [children].
final EdgeInsets padding; 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 /// Called when a list child is dropped into a new position to shuffle the
/// underlying list. /// underlying list.
/// ///
...@@ -122,6 +137,7 @@ class _ReorderableListViewState extends State<ReorderableListView> { ...@@ -122,6 +137,7 @@ class _ReorderableListViewState extends State<ReorderableListView> {
scrollDirection: widget.scrollDirection, scrollDirection: widget.scrollDirection,
onReorder: widget.onReorder, onReorder: widget.onReorder,
padding: widget.padding, padding: widget.padding,
reverse: widget.reverse,
); );
}, },
); );
...@@ -146,6 +162,7 @@ class _ReorderableListContent extends StatefulWidget { ...@@ -146,6 +162,7 @@ class _ReorderableListContent extends StatefulWidget {
@required this.scrollDirection, @required this.scrollDirection,
@required this.padding, @required this.padding,
@required this.onReorder, @required this.onReorder,
@required this.reverse,
}); });
final Widget header; final Widget header;
...@@ -153,6 +170,7 @@ class _ReorderableListContent extends StatefulWidget { ...@@ -153,6 +170,7 @@ class _ReorderableListContent extends StatefulWidget {
final Axis scrollDirection; final Axis scrollDirection;
final EdgeInsets padding; final EdgeInsets padding;
final ReorderCallback onReorder; final ReorderCallback onReorder;
final bool reverse;
@override @override
_ReorderableListContentState createState() => _ReorderableListContentState(); _ReorderableListContentState createState() => _ReorderableListContentState();
...@@ -544,16 +562,25 @@ class _ReorderableListContentState extends State<_ReorderableListContent> with T ...@@ -544,16 +562,25 @@ class _ReorderableListContentState extends State<_ReorderableListContent> with T
); );
break; break;
} }
wrappedChildren.add(_wrap( if (widget.reverse) {
finalDropArea, wrappedChildren.insert(0, _wrap(
widget.children.length, finalDropArea,
constraints), widget.children.length,
); constraints),
);
} else {
wrappedChildren.add(_wrap(
finalDropArea,
widget.children.length,
constraints),
);
}
return SingleChildScrollView( return SingleChildScrollView(
scrollDirection: widget.scrollDirection, scrollDirection: widget.scrollDirection,
child: _buildContainerForScrollDirection(children: wrappedChildren), child: _buildContainerForScrollDirection(children: wrappedChildren),
padding: widget.padding, padding: widget.padding,
controller: _scrollController, controller: _scrollController,
reverse: widget.reverse,
); );
}); });
} }
......
...@@ -900,6 +900,30 @@ void main() { ...@@ -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. // 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