Flutter: How to implement Drag And Drop (ReOrderable)GridView under 2 minutes

Ishan Jaiswal
Aug 30, 2020 · 5 min read
How to implement Drag And Drop GridView Under 2 Minutes

Hello there! Recently I was working on a flutter project where I wanted to implement a drag and drop / reorderable GridView. To my surprise, at the time I couldn’t find any help as to how I can create one.

Eventually, after long days, I was able to piece together a working logic which made my GridView draggable. So I am here today with a very quick guide on how to achieve this. Ready! Get! Set! Go!!!

Installation

So for making it easier for everyone we will be using a plugin Drag And Drop GridView developed by DevOrbiter.

Go ahead and add the dependency to your project’s pubspec.yaml file, like below.

dependencies:   
drag_and_drop_gridview: ^1.0.4

Implementation

Now that we have installed the plugin we can move forward with the implementation of the drag and drop logic.

This plugin, however, has some required parameters that you need to pass: gridDelegate, itemBuilder, onWillAccept, and onReorder.

gridDelegate

This is the same as we find it in the official gridview of Flutter.

gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 3 / 4.5,
),
gridDelegate Flutter

itemBuilder

This is the same as we find it in the official gridview of Flutter.

itemBuilder: (context, index) => Card(
elevation: 2,
child: Center(
child: Text(_animals[index]),
),
itemBuilder with given parameters

onWillAccept

This function allows you to validate if you want to accept the change in the order of the gridViewItems. If you always want to accept the change simply return true

// _animals = ['cat','dog','kitten','puppy']onWillAccept: (oldIndex, newIndex) {
// Implement you own logic
// Example reject the reorder if the moving item's destination value is cat"
if (_animals[newIndex] == "cat"){
return false;
}
return true, // If you want to accept the child return true or else return false
},
onWillAccept with the given logic

onReorder

This function deals with changing the index of the newly arranged gridViewItems.

onReorder: (oldIndex, newIndex) {
// You can also implement on your own logic on reorderable

int indexOfFirstItem = _animals.indexOf(_animals[oldIndex]);
int indexOfSecondItem = _animals.indexOf(_animals[newIndex]);

if (indexOfFirstItem > indexOfSecondItem) {
for (int i = _animals.indexOf(_animals[oldIndex]);
i > _animals.indexOf(_animals[newIndex]);
i--) {
var tmp = _animals[i - 1];
_animals[i - 1] = _animals[i];
_animals[i] = tmp;
}
} else {
for (int i = _animals.indexOf(_animals[oldIndex]);
i < _animals.indexOf(_animals[newIndex]);
i++) {
var tmp = _animals[i + 1];
_animals[i + 1] = _animals[i];
_animals[i] = tmp;
}
}
setState(() {});
},

Final Result

These are the final code showing how you can achieve the Reorderable / Re-Indexing feature in DragAndDropGridView.

Vertical Drag And Drop GridView

import 'package:drag_and_drop_gridview/devdrag.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:async';

import 'package:flutter/services.dart';

void main() {
runApp(MyApp());
}

class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
List<String> _imageUris = [
"https://images.pexels.com/photos/4466054/pexels-photo-4466054.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
"https://images.pexels.com/photos/4561739/pexels-photo-4561739.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/4507967/pexels-photo-4507967.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/4321194/pexels-photo-4321194.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/1053924/pexels-photo-1053924.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/1624438/pexels-photo-1624438.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260",
"https://images.pexels.com/photos/1144687/pexels-photo-1144687.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260",
"https://images.pexels.com/photos/2589010/pexels-photo-2589010.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260"
];

int variableSet = 0;
ScrollController _scrollController;
double width;
double height;

@override
void initState() {
super.initState();
}

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Drag And drop Plugging'),
),
body: Center(
child: DragAndDropGridView(
controller: _scrollController,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 3 / 4.5,
),
padding: EdgeInsets.all(20),
itemBuilder: (context, index) => Card(
elevation: 2,
child: LayoutBuilder(builder: (context, costrains) {
if (variableSet == 0) {
height = costrains.maxHeight;
width = costrains.maxWidth;
variableSet++;
}
return GridTile(
child: Image.network(
_imageUris[index],
height: height,
width: width,
),
);
}),
),
itemCount: _imageUris.length,
onWillAccept: (oldIndex, newIndex) => true,
onReorder: (oldIndex, newIndex) {

// You can also implement on your own logic on reorderable

int indexOfFirstItem = _imageUris.indexOf(_imageUris[oldIndex]);
int indexOfSecondItem = _imageUris.indexOf(_imageUris[newIndex]);

if (indexOfFirstItem > indexOfSecondItem) {
for (int i = _imageUris.indexOf(_imageUris[oldIndex]);
i > _imageUris.indexOf(_imageUris[newIndex]);
i--) {
var tmp = _imageUris[i - 1];
_imageUris[i - 1] = _imageUris[i];
_imageUris[i] = tmp;
}
} else {
for (int i = _imageUris.indexOf(_imageUris[oldIndex]);
i < _imageUris.indexOf(_imageUris[newIndex]);
i++) {
var tmp = _imageUris[i + 1];
_imageUris[i + 1] = _imageUris[i];
_imageUris[i] = tmp;
}
}
setState(() {});
},
),
),
),
);
}
}
Drag And Drop GridView Vertical (ReOrderable)

Horizontal Drag And Drop GridView

In order to use implement the horizontal GridView all you need to do is just use the horizontal constructor everything else may remain the same.

import 'package:drag_and_drop_gridview/devdrag.dart';
import 'package:drag_and_drop_gridview/drag.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:async';
import 'package:flutter/services.dart';void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<String> _imageUris = [
"https://images.pexels.com/photos/4466054/pexels-photo-4466054.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
"https://images.pexels.com/photos/4561739/pexels-photo-4561739.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/4507967/pexels-photo-4507967.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/4321194/pexels-photo-4321194.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/1053924/pexels-photo-1053924.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/1624438/pexels-photo-1624438.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260",
"https://images.pexels.com/photos/1144687/pexels-photo-1144687.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260",
"https://images.pexels.com/photos/2589010/pexels-photo-2589010.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260"
];
int variableSet = 0, variableSetHeader = 0;
ScrollController _scrollController;
double width;
double height;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Horizontal DragAndDropGridView'),
),
body: Center(
child: DragAndDropGridView.horizontal(
controller: _scrollController,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 5,
childAspectRatio: 3 / 4.5,
),
padding: EdgeInsets.all(20),
itemBuilder: (context, index) => Card(
elevation: 2,
child: LayoutBuilder(builder: (context, costrains) {
if (variableSet == 0) {
height = costrains.maxHeight;
width = costrains.maxWidth;
variableSet++;
}
return GridTile(
key: index == 4 ? Key("12") : null,
child: Image.network(
_imageUris[index],
fit: BoxFit.cover,
height: height,
width: width,
),
);
}),
),
itemCount: _imageUris.length,
onWillAccept: (oldIndex, newIndex) => true,
onReorder: (oldIndex, newIndex) {
int indexOfFirstItem = _imageUris.indexOf(_imageUris[oldIndex]);
int indexOfSecondItem = _imageUris.indexOf(_imageUris[newIndex]);
if (indexOfFirstItem > indexOfSecondItem) {
for (int i = _imageUris.indexOf(_imageUris[oldIndex]);
i > _imageUris.indexOf(_imageUris[newIndex]);
i--) {
var tmp = _imageUris[i - 1];
_imageUris[i - 1] = _imageUris[i];
_imageUris[i] = tmp;
}
} else {
for (int i = _imageUris.indexOf(_imageUris[oldIndex]);
i < _imageUris.indexOf(_imageUris[newIndex]);
i++) {
var tmp = _imageUris[i + 1];
_imageUris[i + 1] = _imageUris[i];
_imageUris[i] = tmp;
}
}
setState(() {});
},
),
),
),
);
}
}
Drag And Drop GridView Horizontal (ReOrderable)

Conclusion

So there it is! A simple drag and drop gridview implemented with a reorderable logic within 2 minutes.

There are many more possibilities with this plugin, I will be posting more variations that can be achieved with this amazing plugin.

And if you are already absolutely in love with the plugin or it helped you in a difficult spot don’t forget to support the developers at Github and be sure to buy them a coffee

If you loved the article and learned something new smash the clap button x100 it will motivate me for writing more amazing articles.

https://www.twitter.com/FlutterComm

Flutter Community

Articles and Stories from the Flutter Community