Flutter: How to implement Drag And Drop (ReOrderable)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,
),
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]),
),
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
},
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(() {});
},
),
),
),
);
}
}
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(() {});
},
),
),
),
);
}
}
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.