Unverified Commit 7db172b2 authored by Darren Austin's avatar Darren Austin Committed by GitHub

Added a ReorderableListView.builder constructor (#74697)

Added constructor parameters to the ReorderableList that were missing from ScrollView. Also replace a lot of doc comments with macro templates to reduce duplication.
parent 0af04b2c
......@@ -68,10 +68,10 @@ typedef ReorderCallback = void Function(int oldIndex, int newIndex);
/// The [child] will be the item that is being dragged, and [index] is the
/// position of the item in the list.
///
/// The [animation] will be driven from 0 to 1.0 while the item is being picked
/// up during a drag operation, and reversed from 1.0 to 0 when the item is
/// dropped. This can be used to animate properties of the proxy like an
/// elevation or border.
/// The [animation] will be driven forward from 0.0 to 1.0 while the item is
/// being picked up during a drag operation, and reversed from 1.0 to 0.0 when
/// the item is dropped. This can be used to animate properties of the proxy
/// like an elevation or border.
///
/// The returned value will typically be the [child] wrapped in other widgets.
typedef ReorderItemProxyDecorator = Widget Function(Widget child, int index, Animation<double> animation);
......@@ -113,16 +113,23 @@ class ReorderableList extends StatefulWidget {
required this.itemCount,
required this.onReorder,
this.proxyDecorator,
this.padding,
this.scrollDirection = Axis.vertical,
this.reverse = false,
this.controller,
this.primary,
this.physics,
this.shrinkWrap = false,
this.padding,
this.anchor = 0.0,
this.cacheExtent,
this.dragStartBehavior = DragStartBehavior.start,
this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
this.restorationId,
this.clipBehavior = Clip.hardEdge,
}) : assert(itemCount >= 0),
super(key: key);
/// {@template flutter.widgets.reorderable_list.itemBuilder}
/// Called, as needed, to build list item widgets.
///
/// List items are only built when they're scrolled into view.
......@@ -133,91 +140,76 @@ class ReorderableList extends StatefulWidget {
/// unique [Key], and should have some kind of listener to start the drag
/// (usually a [ReorderableDragStartListener] or
/// [ReorderableDelayedDragStartListener]).
/// {@endtemplate}
final IndexedWidgetBuilder itemBuilder;
/// {@template flutter.widgets.reorderable_list.itemCount}
/// The number of items in the list.
///
/// It must be a non-negative integer. When zero, nothing is displayed and
/// the widget occupies no space.
/// {@endtemplate}
final int itemCount;
/// {@template flutter.widgets.reorderable_list.onReorder}
/// A callback used by the list to report that a list item has been dragged
/// to a new location in the list and the application should update the order
/// of the items.
/// {@endtemplate}
final ReorderCallback onReorder;
/// {@template flutter.widgets.reorderable_list.proxyDecorator}
/// A callback that allows the app to add an animated decoration around
/// an item when it is being dragged.
/// {@endtemplate}
final ReorderItemProxyDecorator? proxyDecorator;
/// The axis along which the list of items scrolls.
/// {@template flutter.widgets.reorderable_list.padding}
/// The amount of space by which to inset the list contents.
///
/// Defaults to [Axis.vertical].
/// It defaults to `EdgeInsets.all(0)`.
/// {@endtemplate}
final EdgeInsetsGeometry? padding;
/// {@macro flutter.widgets.scroll_view.scrollDirection}
final Axis scrollDirection;
/// 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.
/// {@macro flutter.widgets.scroll_view.reverse}
final bool reverse;
/// An object that can be used to control the scroll view's scroll offset.
///
/// Must be null if [primary] is true.
///
/// A [ScrollController] serves several purposes. It can be used to control
/// the initial scroll position (see [ScrollController.initialScrollOffset]).
/// It can be used to control whether the scroll view should automatically
/// save and restore its scroll position in the [PageStorage] (see
/// [ScrollController.keepScrollOffset]). It can be used to read the current
/// scroll position (see [ScrollController.offset]), or change it (see
/// [ScrollController.animateTo]).
/// {@macro flutter.widgets.scroll_view.controller}
final ScrollController? controller;
/// Whether this is the primary scroll view associated with the parent
/// [PrimaryScrollController].
///
/// On iOS, this identifies the scroll view that will scroll to top in
/// response to a tap in the status bar.
///
/// Defaults to true when [scrollDirection] is [Axis.vertical] and
/// [controller] is null.
/// {@macro flutter.widgets.scroll_view.primary}
final bool? primary;
/// How the scroll view should respond to user input.
///
/// For example, determines how the scroll view continues to animate after the
/// user stops dragging the scroll view.
///
/// Defaults to matching platform conventions.
/// {@macro flutter.widgets.scroll_view.physics}
final ScrollPhysics? physics;
/// Whether the extent of the scroll view in the [scrollDirection] should be
/// determined by the contents being viewed.
///
/// If the scroll view does not shrink wrap, then the scroll view will expand
/// to the maximum allowed size in the [scrollDirection]. If the scroll view
/// has unbounded constraints in the [scrollDirection], then [shrinkWrap] must
/// be true.
///
/// Shrink wrapping the content of the scroll view is significantly more
/// expensive than expanding to the maximum allowed size because the content
/// can expand and contract during scrolling, which means the size of the
/// scroll view needs to be recomputed whenever the scroll position changes.
///
/// Defaults to false.
/// {@macro flutter.widgets.scroll_view.shrinkWrap}
final bool shrinkWrap;
/// The amount of space by which to inset the children.
final EdgeInsetsGeometry? padding;
/// {@macro flutter.widgets.scroll_view.anchor}
final double anchor;
/// {@macro flutter.rendering.RenderViewportBase.cacheExtent}
final double? cacheExtent;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
/// {@macro flutter.widgets.scroll_view.keyboardDismissBehavior}
///
/// The default is [ScrollViewKeyboardDismissBehavior.manual]
final ScrollViewKeyboardDismissBehavior keyboardDismissBehavior;
/// {@macro flutter.widgets.scrollable.restorationId}
final String? restorationId;
/// {@macro flutter.material.Material.clipBehavior}
///
/// Defaults to [Clip.hardEdge].
final Clip clipBehavior;
/// The state from the closest instance of this class that encloses the given
/// context.
......@@ -334,6 +326,12 @@ class ReorderableListState extends State<ReorderableList> {
primary: widget.primary,
physics: widget.physics,
shrinkWrap: widget.shrinkWrap,
anchor: widget.anchor,
cacheExtent: widget.cacheExtent,
dragStartBehavior: widget.dragStartBehavior,
keyboardDismissBehavior: widget.keyboardDismissBehavior,
restorationId: widget.restorationId,
clipBehavior: widget.clipBehavior,
slivers: <Widget>[
SliverPadding(
padding: widget.padding ?? EdgeInsets.zero,
......@@ -386,28 +384,16 @@ class SliverReorderableList extends StatefulWidget {
}) : assert(itemCount >= 0),
super(key: key);
/// Called, as needed, to build list item widgets.
///
/// List items are only built when they're scrolled into view.
///
/// The [IndexedWidgetBuilder] index parameter indicates the item's
/// position in the list. The value of the index parameter will be between
/// zero and one less than [itemCount]. All items in the list should have a
/// unique [Key], and should have some kind of listener to start the drag
/// (usually a [ReorderableDragStartListener] or
/// [ReorderableDelayedDragStartListener]).
/// {@macro flutter.widgets.reorderable_list.itemBuilder}
final IndexedWidgetBuilder itemBuilder;
/// The number of items in the list.
/// {@macro flutter.widgets.reorderable_list.itemCount}
final int itemCount;
/// A callback used by the list to report that a list item has been dragged
/// to a new location in the list and the application should update the order
/// of the items.
/// {@macro flutter.widgets.reorderable_list.onReorder}
final ReorderCallback onReorder;
/// A callback that allows the app to add an animated decoration around
/// an item when it is being dragged.
/// {@macro flutter.widgets.reorderable_list.proxyDecorator}
final ReorderItemProxyDecorator? proxyDecorator;
@override
......
......@@ -109,11 +109,14 @@ abstract class ScrollView extends StatelessWidget {
physics = physics ?? (primary == true || (primary == null && controller == null && identical(scrollDirection, Axis.vertical)) ? const AlwaysScrollableScrollPhysics() : null),
super(key: key);
/// {@template flutter.widgets.scroll_view.scrollDirection}
/// The axis along which the scroll view scrolls.
///
/// Defaults to [Axis.vertical].
/// {@endtemplate}
final Axis scrollDirection;
/// {@template flutter.widgets.scroll_view.reverse}
/// Whether the scroll view scrolls in the reading direction.
///
/// For example, if the reading direction is left-to-right and
......@@ -126,8 +129,10 @@ abstract class ScrollView extends StatelessWidget {
/// when [reverse] is true.
///
/// Defaults to false.
/// {@endtemplate}
final bool reverse;
/// {@template flutter.widgets.scroll_view.controller}
/// An object that can be used to control the position to which this scroll
/// view is scrolled.
///
......@@ -140,8 +145,10 @@ abstract class ScrollView extends StatelessWidget {
/// [ScrollController.keepScrollOffset]). It can be used to read the current
/// scroll position (see [ScrollController.offset]), or change it (see
/// [ScrollController.animateTo]).
/// {@endtemplate}
final ScrollController? controller;
/// {@template flutter.widgets.scroll_view.primary}
/// Whether this is the primary scroll view associated with the parent
/// [PrimaryScrollController].
///
......@@ -156,11 +163,13 @@ abstract class ScrollView extends StatelessWidget {
///
/// On iOS, this also identifies the scroll view that will scroll to top in
/// response to a tap in the status bar.
/// {@endtemplate}
///
/// Defaults to true when [scrollDirection] is [Axis.vertical] and
/// [controller] is null.
final bool primary;
/// {@template flutter.widgets.scroll_view.physics}
/// How the scroll view should respond to user input.
///
/// For example, determines how the scroll view continues to animate after the
......@@ -195,8 +204,10 @@ abstract class ScrollView extends StatelessWidget {
/// dynamically, which can be relatively expensive, and it would be
/// inefficient to speculatively create this object each frame to see if the
/// physics should be updated.)
/// {@endtemplate}
final ScrollPhysics? physics;
/// {@template flutter.widgets.scroll_view.shrinkWrap}
/// Whether the extent of the scroll view in the [scrollDirection] should be
/// determined by the contents being viewed.
///
......@@ -211,6 +222,7 @@ abstract class ScrollView extends StatelessWidget {
/// scroll view needs to be recomputed whenever the scroll position changes.
///
/// Defaults to false.
/// {@endtemplate}
final bool shrinkWrap;
/// The first child in the [GrowthDirection.forward] growth direction.
......@@ -232,6 +244,7 @@ abstract class ScrollView extends StatelessWidget {
/// * [anchor], which controls where the [center] as aligned in the viewport.
final Key? center;
/// {@template flutter.widgets.scroll_view.anchor}
/// The relative position of the zero scroll offset.
///
/// For example, if [anchor] is 0.5 and the [AxisDirection] determined by
......@@ -240,6 +253,7 @@ abstract class ScrollView extends StatelessWidget {
/// within the viewport. If the [anchor] is 1.0, and the axis direction is
/// [AxisDirection.right], then the zero scroll offset is on the left edge of
/// the viewport.
/// {@endtemplate}
final double anchor;
/// {@macro flutter.rendering.RenderViewportBase.cacheExtent}
......@@ -263,8 +277,10 @@ abstract class ScrollView extends StatelessWidget {
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
/// {@template flutter.widgets.scroll_view.keyboardDismissBehavior}
/// [ScrollViewKeyboardDismissBehavior] the defines how this [ScrollView] will
/// dismiss the keyboard automatically.
/// {@endtemplate}
final ScrollViewKeyboardDismissBehavior keyboardDismissBehavior;
/// {@macro flutter.widgets.scrollable.restorationId}
......
......@@ -1153,6 +1153,34 @@ void main() {
});
testWidgets('ReorderableListView.builder asserts on negative childCount', (WidgetTester tester) async {
expect(() => ReorderableListView.builder(
itemBuilder: (BuildContext context, int index) {
return const SizedBox();
},
itemCount: -1,
onReorder: (int from, int to) {},
), throwsAssertionError);
});
testWidgets('ReorderableListView.builder only creates the children it needs', (WidgetTester tester) async {
final Set<int> itemsCreated = <int>{};
await tester.pumpWidget(MaterialApp(
home: ReorderableListView.builder(
itemBuilder: (BuildContext context, int index) {
itemsCreated.add(index);
return Text(index.toString(), key: ValueKey<int>(index));
},
itemCount: 1000,
onReorder: (int from, int to) {},
),
));
// Should have only created the first 18 items.
expect(itemsCreated, <int>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17});
});
testWidgets('ReorderableListView can be reversed', (WidgetTester tester) async {
final Widget reorderableListView = ReorderableListView(
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