ReorderableGridView class

A scrollable, reorderable, 2D array of widgets.

The main axis direction of a grid is the direction in which it scrolls (the scrollDirection).

The most commonly used grid layouts are ReorderableGridView.count, which creates a layout with a fixed number of tiles in the cross axis, and ReorderableGridView.extent, which creates a layout with tiles that have a maximum cross-axis extent. A custom SliverGridDelegate can produce an arbitrary 2D arrangement of children, including arrangements that are unaligned or overlapping.

To create a grid with a large (or infinite) number of children, use the ReorderableGridView.builder constructor with either a SliverGridDelegateWithFixedCrossAxisCount or a SliverGridDelegateWithMaxCrossAxisExtent for the gridDelegate.

To create a linear array of reorderable children, use a ReorderableList.

To control the initial scroll offset of the scroll view, provide a controller with its ScrollController.initialScrollOffset property set.

Transitioning to CustomScrollView

A ReorderableGridView is basically a CustomScrollView with a single SliverReorderableGrid in its CustomScrollView.slivers property.

If ReorderableGridView is no longer sufficient, for example because the scroll view is to have both a grid and a list, or because the grid is to be combined with a SliverAppBar, etc, it is straight-forward to port code from using ReorderableGridView to using CustomScrollView directly.

The key, scrollDirection, reverse, controller, primary, physics, and shrinkWrap properties on ReorderableGridView map directly to the identically named properties on CustomScrollView.

The CustomScrollView.slivers property should be a list containing just a SliverGrid.

the gridDelegate property on the ReorderableGridView corresponds to the SliverGrid.gridDelegate property.

The ReorderableGridView, ReorderableGridView.count, and ReorderableGridView.extent constructors' children arguments correspond to the childrenDelegate being a SliverChildListDelegate with that same argument. The ReorderableGridView.builder constructor's itemBuilder and childCount arguments correspond to the childrenDelegate being a SliverChildBuilderDelegate with the matching arguments.

The ReorderableGridView.count and ReorderableGridView.extent constructors create custom grid delegates, and have equivalently named constructors on SliverGrid to ease the transition: SliverGrid.count and SliverGrid.extent respectively.

The padding property corresponds to having a SliverPadding in the CustomScrollView.slivers property instead of the grid itself, and having the SliverGrid instead be a child of the SliverPadding.

Once code has been ported to use CustomScrollView, other slivers, such as SliverList or SliverAppBar, can be put in the CustomScrollView.slivers list.

{@tool snippet} This example demonstrates how to create a ReorderableGridView with two columns. The children are spaced apart using the crossAxisSpacing and mainAxisSpacing properties.

ReorderableGridView.count(
  primary: false,
  padding: const EdgeInsets.all(20),
  crossAxisSpacing: 10,
  mainAxisSpacing: 10,
  crossAxisCount: 2,
  onReorder: (int oldIndex, int newIndex) {
    print('from: $oldIndex, to: $newIndex);
  },
  children: <Widget>[
    Container(
      padding: const EdgeInsets.all(8),
      child: const Text("He'd have you all unravel at the"),
      color: Colors.teal[100],
    ),
    Container(
      padding: const EdgeInsets.all(8),
      child: const Text('Heed not the rabble'),
      color: Colors.teal[200],
    ),
    Container(
      padding: const EdgeInsets.all(8),
      child: const Text('Sound of screams but the'),
      color: Colors.teal[300],
    ),
    Container(
      padding: const EdgeInsets.all(8),
      child: const Text('Who scream'),
      color: Colors.teal[400],
    ),
    Container(
      padding: const EdgeInsets.all(8),
      child: const Text('Revolution is coming...'),
      color: Colors.teal[500],
    ),
    Container(
      padding: const EdgeInsets.all(8),
      child: const Text('Revolution, they...'),
      color: Colors.teal[600],
    ),
  ],
)

{@end-tool}

{@tool snippet} This example shows how to create the same grid as the previous example using a CustomScrollView and a SliverGrid.

The CustomScrollView contains a SliverGrid that displays six children with different background colors arranged in two columns

CustomScrollView(
  primary: false,
  slivers: <Widget>[
    SliverPadding(
      padding: const EdgeInsets.all(20),
      sliver: SliverReorderableGrid.count(
        crossAxisSpacing: 10,
        mainAxisSpacing: 10,
        crossAxisCount: 2,
        onReorder: (int oldIndex, int newIndex) {
          print('from: $oldIndex, to: $newIndex);
        },
        children: <Widget>[
          Container(
            padding: const EdgeInsets.all(8),
            child: const Text("He'd have you all unravel at the"),
            color: Colors.green[100],
          ),
          Container(
            padding: const EdgeInsets.all(8),
            child: const Text('Heed not the rabble'),
            color: Colors.green[200],
          ),
          Container(
            padding: const EdgeInsets.all(8),
            child: const Text('Sound of screams but the'),
            color: Colors.green[300],
          ),
          Container(
            padding: const EdgeInsets.all(8),
            child: const Text('Who scream'),
            color: Colors.green[400],
          ),
          Container(
            padding: const EdgeInsets.all(8),
            child: const Text('Revolution is coming...'),
            color: Colors.green[500],
          ),
          Container(
            padding: const EdgeInsets.all(8),
            child: const Text('Revolution, they...'),
            color: Colors.green[600],
          ),
        ],
      ),
    ),
  ],
)

{@end-tool}

By default, ReorderableGridView will automatically pad the limits of the grids's scrollable to avoid partial obstructions indicated by MediaQuery's padding. To avoid this behavior, override with a zero padding property.

{@tool snippet} The following example demonstrates how to override the default top padding using MediaQuery.removePadding.

Widget myWidget(BuildContext context) {
  return MediaQuery.removePadding(
    context: context,
    removeTop: true,
    child: ReorderableGridView.builder(
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 3,
      ),
      itemCount: 300,
      itemBuilder: (BuildContext context, int index) {
        return Card(
          color: Colors.amber,
          child: Center(child: Text('$index')),
        );
      }
    ),
  );
}

{@end-tool}

See also:

Inheritance

Constructors

ReorderableGridView({Key? key, Axis scrollDirection = Axis.vertical, bool reverse = false, ScrollController? controller, bool? primary, ScrollPhysics? physics, bool shrinkWrap = false, EdgeInsetsGeometry? padding, required SliverGridDelegate gridDelegate, required ReorderCallback onReorder, IndexedValueGetter<bool> itemDragEnable = _defaultItemDragEnable, double? cacheExtent, List<Widget> children = const <Widget>[], int? semanticChildCount, DragStartBehavior dragStartBehavior = DragStartBehavior.start, Clip clipBehavior = Clip.hardEdge, ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual, String? restorationId, double anchor = 0.0, ReorderItemProxyDecorator? proxyDecorator, bool? autoScroll, void onReorderStart(int index)?})
Creates a scrollable, 2D array of widgets with a custom SliverGridDelegate.
ReorderableGridView.builder({Key? key, Axis scrollDirection = Axis.vertical, bool reverse = false, ScrollController? controller, bool? primary, ScrollPhysics? physics, bool shrinkWrap = false, EdgeInsetsGeometry? padding, required SliverGridDelegate gridDelegate, required IndexedWidgetBuilder itemBuilder, required int itemCount, required ReorderCallback onReorder, IndexedValueGetter<bool> itemDragEnable = _defaultItemDragEnable, double? cacheExtent, int? semanticChildCount, DragStartBehavior dragStartBehavior = DragStartBehavior.start, ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual, String? restorationId, Clip clipBehavior = Clip.hardEdge, double anchor = 0.0, ReorderItemProxyDecorator? proxyDecorator, bool? autoScroll, void onReorderStart(int index)?})
Creates a scrollable, 2D array of widgets that are created on demand.
const
ReorderableGridView.count({Key? key, Axis scrollDirection = Axis.vertical, bool reverse = false, ScrollController? controller, bool? primary, ScrollPhysics? physics, bool shrinkWrap = false, EdgeInsetsGeometry? padding, required int crossAxisCount, required ReorderCallback onReorder, IndexedValueGetter<bool> itemDragEnable = _defaultItemDragEnable, double mainAxisSpacing = 0.0, double crossAxisSpacing = 0.0, double childAspectRatio = 1.0, double? cacheExtent, List<Widget> children = const <Widget>[], int? semanticChildCount, DragStartBehavior dragStartBehavior = DragStartBehavior.start, ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual, String? restorationId, Clip clipBehavior = Clip.hardEdge, double anchor = 0.0, ReorderItemProxyDecorator? proxyDecorator, bool? autoScroll, void onReorderStart(int index)?})
Creates a scrollable, 2D array of widgets with a fixed number of tiles in the cross axis.
ReorderableGridView.extent({Key? key, Axis scrollDirection = Axis.vertical, bool reverse = false, ScrollController? controller, bool? primary, ScrollPhysics? physics, bool shrinkWrap = false, EdgeInsetsGeometry? padding, required double maxCrossAxisExtent, required ReorderCallback onReorder, IndexedValueGetter<bool> itemDragEnable = _defaultItemDragEnable, double mainAxisSpacing = 0.0, double crossAxisSpacing = 0.0, double childAspectRatio = 1.0, double? cacheExtent, List<Widget> children = const <Widget>[], int? semanticChildCount, DragStartBehavior dragStartBehavior = DragStartBehavior.start, ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual, String? restorationId, Clip clipBehavior = Clip.hardEdge, double anchor = 0.0, ReorderItemProxyDecorator? proxyDecorator, bool? autoScroll, void onReorderStart(int index)?})
Creates a scrollable, 2D array of widgets with tiles that each have a maximum cross-axis extent.

Properties

anchor double
The relative position of the zero scroll offset.
final
autoScroll bool?
Overrides if autoscrolling is enabled. Defaults to false if physics is NeverScrollableScrollPhysics
final
cacheExtent double?
The viewport has an area before and after the visible area to cache items that are about to become visible when the user scrolls.
final
clipBehavior Clip
The content will be clipped (or not) according to this option.
final
controller ScrollController?
final
dragStartBehavior DragStartBehavior
Determines the way that drag start behavior is handled.
final
gridDelegate SliverGridDelegate
A delegate that controls the layout of the children within the ReorderableGridView.
final
hashCode int
The hash code for this object.
no setterinherited
itemBuilder IndexedWidgetBuilder
Called, as needed, to build list item widgets.
final
itemCount int
The number of items in the list.
final
itemDragEnable → IndexedValueGetter<bool>
Allows you to manually overwrite which items can be dragged or not
final
key Key?
Controls how one widget replaces another widget in the tree.
finalinherited
keyboardDismissBehavior ScrollViewKeyboardDismissBehavior
ScrollViewKeyboardDismissBehavior the defines how this ScrollView will dismiss the keyboard automatically.
final
onReorder ReorderCallback
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.
final
onReorderStart → (void Function(int index)?)
A callback that is called when an item drag has started.
final
padding EdgeInsetsGeometry?
final
physics ScrollPhysics?
How the scroll view should respond to user input.
final
primary bool?
Whether this is the primary scroll view associated with the parent PrimaryScrollController.
final
proxyDecorator ReorderItemProxyDecorator?
A callback that allows the app to add an animated decoration around an item when it is being dragged.
final
restorationId String?
Restoration ID to save and restore the scroll offset of the scrollable.
final
reverse bool
Whether the scroll view scrolls in the reading direction.
final
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
scrollDirection Axis
The Axis along which the scroll view's offset increases.
final
semanticChildCount int?
final
shrinkWrap bool
Whether the extent of the scroll view in the scrollDirection should be determined by the contents being viewed.
final

Methods

createElement() StatefulElement
Creates a StatefulElement to manage this widget's location in the tree.
inherited
createState() ReorderableGridViewState
Creates the mutable state for this widget at a given location in the tree.
override
debugDescribeChildren() List<DiagnosticsNode>
Returns a list of DiagnosticsNode objects describing this node's children.
inherited
debugFillProperties(DiagnosticPropertiesBuilder properties) → void
Add additional properties associated with the node.
inherited
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
toDiagnosticsNode({String? name, DiagnosticsTreeStyle? style}) DiagnosticsNode
Returns a debug representation of the object that is used by debugging tools and by DiagnosticsNode.toStringDeep.
inherited
toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) String
A string representation of this object.
inherited
toStringDeep({String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug}) String
Returns a string representation of this node and its descendants.
inherited
toStringShallow({String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) String
Returns a one-line detailed description of the object.
inherited
toStringShort() String
A short, textual description of this widget.
inherited

Operators

operator ==(Object other) bool
The equality operator.
inherited