top of page

[Flutter/dart] Create a gridview which can be drag and drop


Overview


We often place gridview in the app, but I wanted to be able to drag and drop them.

In that case, use drag_and_drop_gridview.



Method


Basic


first, install the library

drag_and_drop_gridview: ^1.0.8

import it at the top of dart file.

import 'package:drag_and_drop_gridview/devdrag.dart';

The part of grid view is as below.

Widget _myGrid(){

  return DragAndDropGridView(
    onWillAccept: (oldInd, newInd)=> true,
    onReorder: (oldInd, newInd){
      changeListOrder(
        oldInd: oldInd, newInd: newInd, list: _indexes
      );
    },
    itemCount: ITEM_COUNT,
    gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
      crossAxisCount: 2,
      crossAxisSpacing: CARD_SPACE,
      mainAxisSpacing: 24,
    ),
    itemBuilder: (context, index)=> _itemBuilder(index),
  );
}
int ITEM_COUNT=8;
List<int> _indexes=[];
static const double PADDING=32;
static const double CARD_SPACE=24;
bool _sizeCalced=false;
double _cardSize;

@override
Widget build(BuildContext context) {

  if (!_sizeCalced) {
    _cardSize = (MediaQuery.of(context).size.width - 2 * PADDING - 
            CARD_SPACE) / 2;
    _sizeCalced=true;
  }

  _indexes=List.generate(ITEM_COUNT, (index) => index);

  return Scaffold(
    appBar: AppBar(),
    body: SingleChildScrollView(
      child: Center(
        child: Container(
          padding: const EdgeInsets.all(32),
          child: _myGrid(),
          width: double.infinity,
        ),
      )
    ),
  );
}

About each property


onWillAccept: Whether to allow it if the order is changed by dragging. This time it is allowed unconditionally.


onReorder: Processing when the order is changed. Here, the elements of _indexes are replaced using the following method.

static void changeListOrder({int oldInd, int newInd, List<int> list}){

  int oldVal=list[oldInd];

  if (oldInd<newInd){

    for (int i=oldInd; i<newInd; i++){
      list[i]=list[i+1];
    }
  }
  else{
    for (int i=oldInd; i>newInd; i--){
      list[i]=list[i-1];
    }
  }
  list[newInd]=oldVal;
}

itemCount: Element count. Note that if you forget to set this, an index error will occur in itemBuilder.


gridDelegate: Set grid placement.


itemBuilder: Create individual views. The second argument means the (index)th element. Here, it is as follows.

Widget _itemBuilder(int index){

  int _ind=_indexes[index];

  return Container(
    height: _cardSize,
    width: _cardSize,
    child: Center(
      child: Text(
        _ind.toString(),
        style: const TextStyle(
          fontSize: 24,
          color: Colors.white,
          decoration: TextDecoration.none
        ),
      ),
    ),
    color: Colors.grey,
  );
}

Without decoration: TextDecoration.none, you get a yellow line while dragging.


Also, specify the height and width of the Container explicitly. This is to keep the same size while dragging. This variable _cardSize is calculated at the beginning of build ().


The result is as below.




Change the appearance while dragging


At this rate, the card looks the same when you are dragging and when you are not dragging, so try to change the appearance while dragging.

Set isCustomFeedback to true and specify the widget being dragged in feedback :.


This time, let's change the background color while dragging.

Add an argument to _itemBuilder () to indicate whether it is being dragged.


Widget _itemBuilder(int index, bool onDrag){

  int _ind=_indexes[index];

  return Container(
    height: _cardSize,
    width: _cardSize,
    child: Center(
      child: Text(
        _ind.toString(),
        style: const TextStyle(
          fontSize: 24,
          color: Colors.white,
          decoration: TextDecoration.none
        ),
      ),
    ),
    color: onDrag? Colors.red: Colors.grey,
  );
Widget _myGrid(){

  return DragAndDropGridView(
    onWillAccept: (oldInd, newInd)=> true,
    onReorder: (oldInd, newInd){
      changeListOrder(
        oldInd: oldInd, newInd: newInd, list:_indexes
      );
    },
    itemCount: 8,
    gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
      crossAxisCount: 2,
      crossAxisSpacing: CARD_SPACE,
      mainAxisSpacing: 24,
    ),
    itemBuilder: (context, index)=> _itemBuilder(index, false),
    isCustomFeedback: true,  //here
    feedback: (index)=> _itemBuilder(index, true), //here
  );
}

The result is as below.




Change the appearance of the original place while dragging


Also, while dragging, change the appearance of the location where the card you are dragging originally located.

To do this, set isCustomChildWhenDragging to true and specify the widget to display in the original location in childWhenDragging.


Widget _myGrid(){

  return DragAndDropGridView(
    onWillAccept: (oldInd, newInd)=> true,
    onReorder: (oldInd, newInd){
      changeListOrder(
        oldInd: oldInd, newInd: newInd, list: _indexes
      );
    },
    itemCount: 8,
    gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
      crossAxisCount: 2,
      crossAxisSpacing: CARD_SPACE,
      mainAxisSpacing: 24,
    ),
    itemBuilder: (context, index)=> _itemBuilder(index, false),
    isCustomFeedback: true,
    feedback: (index)=> _itemBuilder(index, true),
    isCustomChildWhenDragging: true,  //here
    childWhenDragging: _childWhenDragging, //here
  );
}
Widget _childWhenDragging(int index){
  return Container(
    width: _cardSize,
    height: _cardSize,
    color: Colors.transparent,
  );
}

This time I made it the same color with the background.


The result is as follows.





Recent Posts

See All

[Flutter/Dart] Format string with TextField

What want to do I want to create an input form using TextField. For example, if the input content is a monetary amount, I would like to display it in 3-digit delimiters with a ¥ prefix. Rather than ha

Comments


Let's do our best with our partner:​ ChatReminder

iphone6.5p2.png

It is an application that achieves goals in a chat format with partners.

google-play-badge.png
Download_on_the_App_Store_Badge_JP_RGB_blk_100317.png

Let's do our best with our partner:​ ChatReminder

納品:iPhone6.5①.png

It is an application that achieves goals in a chat format with partners.

google-play-badge.png
Download_on_the_App_Store_Badge_JP_RGB_blk_100317.png

Theme diary: Decide the theme and record for each genre

It is a diary application that allows you to post and record with themes and sub-themes for each genre.

google-play-badge.png
Download_on_the_App_Store_Badge_JP_RGB_blk_100317.png
bottom of page