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
......@@ -4,6 +4,7 @@
import 'dart:ui' show lerpDouble;
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
......@@ -20,7 +21,7 @@ import 'theme.dart';
/// child that could possibly be displayed in the list view instead of just
/// those children that are actually visible.
///
/// All [children] must have a key.
/// All list items must have a key.
///
/// {@youtube 560 315 https://www.youtube.com/watch?v=3fB1mxOsqJE}
///
......@@ -64,18 +65,32 @@ import 'theme.dart';
///
///{@end-tool}
class ReorderableListView extends StatefulWidget {
/// Creates a reorderable list.
/// Creates a reorderable list from a pre-built list of widgets.
///
/// See also:
///
/// * [ReorderableListView.builder], which allows you to build a reorderable
/// list where the items are built as needed when scrolling the list.
ReorderableListView({
Key? key,
this.header,
required this.children,
required List<Widget> children,
required this.onReorder,
this.scrollController,
this.scrollDirection = Axis.vertical,
this.proxyDecorator,
this.buildDefaultDragHandles = true,
this.padding,
this.header,
this.scrollDirection = Axis.vertical,
this.reverse = false,
this.buildDefaultDragHandles = true,
this.proxyDecorator,
this.scrollController,
this.primary,
this.physics,
this.shrinkWrap = false,
this.anchor = 0.0,
this.cacheExtent,
this.dragStartBehavior = DragStartBehavior.start,
this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
this.restorationId,
this.clipBehavior = Clip.hardEdge,
}) : assert(scrollDirection != null),
assert(onReorder != null),
assert(children != null),
......@@ -84,54 +99,70 @@ class ReorderableListView extends StatefulWidget {
'All children of this widget must have a key.',
),
assert(buildDefaultDragHandles != null),
itemBuilder = ((BuildContext context, int index) => children[index]),
itemCount = children.length,
super(key: key);
/// A non-reorderable header widget to show before the list.
/// Creates a reorderable list from widget items that are created on demand.
///
/// If null, no header will appear before the list.
final Widget? header;
/// The widgets to display.
final List<Widget> children;
/// The [Axis] along which the list scrolls.
///
/// List [children] can only drag along this [Axis].
final Axis scrollDirection;
/// Creates a [ScrollPosition] to manage and determine which portion
/// of the content is visible in the scroll view.
/// This constructor is appropriate for list views with a large number of
/// children because the builder is called only for those children
/// that are actually visible.
///
/// This can be used in many ways, such as setting an initial scroll offset,
/// (via [ScrollController.initialScrollOffset]), reading the current scroll position
/// (via [ScrollController.offset]), or changing it (via [ScrollController.jumpTo] or
/// [ScrollController.animateTo]).
final ScrollController? scrollController;
/// The amount of space by which to inset the [children].
final EdgeInsets? padding;
/// Whether the scroll view scrolls in the reading direction.
/// The `itemBuilder` callback will be called only with indices greater than
/// or equal to zero and less than `itemCount`.
///
/// 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.
/// The `itemBuilder` should always return a non-null widget, and actually
/// create the widget instances when called. Avoid using a builder that
/// returns a previously-constructed widget; if the list view's children are
/// created in advance, or all at once when the [ReorderableListView] itself
/// is created, it is more efficient to use the [ReorderableListView]
/// constructor. Even more efficient, however, is to create the instances
/// on demand using this constructor's `itemBuilder` callback.
///
/// 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.
/// See also:
///
/// Defaults to false.
final bool reverse;
/// * [ReorderableListView], which allows you to build a reorderable
/// list with all the items passed into the constructor.
const ReorderableListView.builder({
Key? key,
required this.itemBuilder,
required this.itemCount,
required this.onReorder,
this.proxyDecorator,
this.buildDefaultDragHandles = true,
this.padding,
this.header,
this.scrollDirection = Axis.vertical,
this.reverse = false,
this.scrollController,
this.primary,
this.physics,
this.shrinkWrap = false,
this.anchor = 0.0,
this.cacheExtent,
this.dragStartBehavior = DragStartBehavior.start,
this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
this.restorationId,
this.clipBehavior = Clip.hardEdge,
}) : assert(scrollDirection != null),
assert(itemCount >= 0),
assert(onReorder != null),
assert(buildDefaultDragHandles != null),
super(key: key);
/// Called when a list child is dropped into a new position to shuffle the
/// underlying list.
///
/// This [ReorderableListView] calls [onReorder] after a list child is dropped
/// into a new position.
/// {@macro flutter.widgets.reorderable_list.itemBuilder}
final IndexedWidgetBuilder itemBuilder;
/// {@macro flutter.widgets.reorderable_list.itemCount}
final int itemCount;
/// {@macro flutter.widgets.reorderable_list.onReorder}
final ReorderCallback onReorder;
/// {@macro flutter.widgets.reorderable_list.proxyDecorator}
final ReorderItemProxyDecorator? proxyDecorator;
/// If true: on desktop platforms, a drag handle is stacked over the
/// center of each item's trailing edge; on mobile platforms, a long
/// press anywhere on the item starts a drag.
......@@ -201,12 +232,56 @@ class ReorderableListView extends StatefulWidget {
///{@end-tool}
final bool buildDefaultDragHandles;
/// A callback that allows the app to add an animated decoration around
/// an item when it is being dragged.
/// {@macro flutter.widgets.reorderable_list.padding}
final EdgeInsets? padding;
/// A non-reorderable header item to show before the items of the list.
///
/// If this is null, a default decoration of a Material widget with
/// an animated elevation will be used.
final ReorderItemProxyDecorator? proxyDecorator;
/// If null, no header will appear before the list.
final Widget? header;
/// {@macro flutter.widgets.scroll_view.scrollDirection}
final Axis scrollDirection;
/// {@macro flutter.widgets.scroll_view.reverse}
final bool reverse;
/// {@macro flutter.widgets.scroll_view.controller}
final ScrollController? scrollController;
/// {@macro flutter.widgets.scroll_view.primary}
/// Defaults to true when [scrollDirection] is [Axis.vertical] and
/// [scrollController] is null.
final bool? primary;
/// {@macro flutter.widgets.scroll_view.physics}
final ScrollPhysics? physics;
/// {@macro flutter.widgets.scroll_view.shrinkWrap}
final bool shrinkWrap;
/// {@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;
@override
_ReorderableListViewState createState() => _ReorderableListViewState();
......@@ -230,15 +305,25 @@ class _ReorderableListViewState extends State<ReorderableListView> {
opaque: true,
builder: (BuildContext context) {
return _ReorderableListContent(
itemBuilder: widget.itemBuilder,
itemCount: widget.itemCount,
onReorder: widget.onReorder,
proxyDecorator: widget.proxyDecorator,
buildDefaultDragHandles: widget.buildDefaultDragHandles,
padding: widget.padding,
header: widget.header,
children: widget.children,
scrollController: widget.scrollController,
scrollDirection: widget.scrollDirection,
padding: widget.padding,
onReorder: widget.onReorder,
reverse: widget.reverse,
buildDefaultDragHandles: widget.buildDefaultDragHandles,
proxyDecorator: widget.proxyDecorator,
scrollController: widget.scrollController,
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,
);
},
);
......@@ -265,26 +350,46 @@ class _ReorderableListViewState extends State<ReorderableListView> {
class _ReorderableListContent extends StatefulWidget {
const _ReorderableListContent({
required this.itemBuilder,
required this.itemCount,
required this.onReorder,
required this.proxyDecorator,
required this.buildDefaultDragHandles,
required this.padding,
required this.header,
required this.children,
required this.scrollController,
required this.scrollDirection,
required this.padding,
required this.onReorder,
required this.reverse,
required this.buildDefaultDragHandles,
required this.proxyDecorator,
required this.scrollController,
required this.primary,
required this.physics,
required this.shrinkWrap,
required this.anchor,
required this.cacheExtent,
required this.dragStartBehavior,
required this.keyboardDismissBehavior,
required this.restorationId,
required this.clipBehavior,
});
final IndexedWidgetBuilder itemBuilder;
final int itemCount;
final ReorderCallback onReorder;
final ReorderItemProxyDecorator? proxyDecorator;
final bool buildDefaultDragHandles;
final EdgeInsets? padding;
final Widget? header;
final List<Widget> children;
final ScrollController? scrollController;
final Axis scrollDirection;
final EdgeInsets? padding;
final ReorderCallback onReorder;
final bool reverse;
final bool buildDefaultDragHandles;
final ReorderItemProxyDecorator? proxyDecorator;
final ScrollController? scrollController;
final bool? primary;
final ScrollPhysics? physics;
final bool shrinkWrap;
final double anchor;
final double? cacheExtent;
final DragStartBehavior dragStartBehavior;
final ScrollViewKeyboardDismissBehavior keyboardDismissBehavior;
final String? restorationId;
final Clip clipBehavior;
@override
_ReorderableListContentState createState() => _ReorderableListContentState();
......@@ -302,7 +407,7 @@ class _ReorderableListContentState extends State<_ReorderableListContent> {
// Create the appropriate semantics actions.
void moveToStart() => reorder(index, 0);
void moveToEnd() => reorder(index, widget.children.length);
void moveToEnd() => reorder(index, widget.itemCount);
void moveBefore() => reorder(index, index - 1);
// To move after, we go to index+2 because we are moving it to the space
// before index+2, which is after the space at index+1.
......@@ -323,7 +428,7 @@ class _ReorderableListContentState extends State<_ReorderableListContent> {
}
// If the item can move to after its current position in the list.
if (index < widget.children.length - 1) {
if (index < widget.itemCount - 1) {
String reorderItemAfter = localizations.reorderItemDown;
if (widget.scrollDirection == Axis.horizontal) {
reorderItemAfter = Directionality.of(context) == TextDirection.ltr
......@@ -349,7 +454,7 @@ class _ReorderableListContentState extends State<_ReorderableListContent> {
}
Widget _itemBuilder(BuildContext context, int index) {
final Widget item = widget.children[index];
final Widget item = widget.itemBuilder(context, index);
// TODO(goderbauer): The semantics stuff should probably happen inside
// _ReorderableItem so the widget versions can have them as well.
......@@ -450,6 +555,15 @@ class _ReorderableListContentState extends State<_ReorderableListContent> {
scrollDirection: widget.scrollDirection,
reverse: widget.reverse,
controller: widget.scrollController,
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>[
if (widget.header != null)
SliverToBoxAdapter(child: widget.header!),
......@@ -457,7 +571,7 @@ class _ReorderableListContentState extends State<_ReorderableListContent> {
padding: listPadding,
sliver: SliverReorderableList(
itemBuilder: _itemBuilder,
itemCount: widget.children.length,
itemCount: widget.itemCount,
onReorder: widget.onReorder,
proxyDecorator: widget.proxyDecorator ?? _proxyDecorator,
),
......
......@@ -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