Android GridView reorder elements via Drag and Drop

37,928

Solution 1

If you don't resolve this problem I will provide my code. But it works on Android 3.0 and above, because I use android drag-n-drop framework

grid = (GridView) findViewById(R.id.grid);
grid.setAdapter(new DragGridAdapter(items, getActivity()));

....

grid.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {

            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                GridView parent = (GridView) v;

                int x = (int) event.getX();
                int y = (int) event.getY();

                int position = parent.pointToPosition(x, y);
                if (position > AdapterView.INVALID_POSITION) {

                    int count = parent.getChildCount();
                    for (int i = 0; i < count; i++) {
                        View curr = parent.getChildAt(i);
                        curr.setOnDragListener(new View.OnDragListener() {

                            @Override
                            public boolean onDrag(View v, DragEvent event) {

                                boolean result = true;
                                int action = event.getAction();
                                switch (action) {
                                case DragEvent.ACTION_DRAG_STARTED:
                                    break;
                                case DragEvent.ACTION_DRAG_LOCATION:
                                    break;
                                case DragEvent.ACTION_DRAG_ENTERED:
                                    v.setBackgroundResource(R.drawable.shape_image_view_small_gallery_selected);
                                    break;
                                case DragEvent.ACTION_DRAG_EXITED:
                                    v.setBackgroundResource(R.drawable.shape_image_view_small_gallery_unselected);
                                    break;
                                case DragEvent.ACTION_DROP:
                                    if (event.getLocalState() == v) {
                                        result = false;
                                    } else {
                                        View droped = (View) event.getLocalState();
                                        GridItem dropItem = ((DragGridItemHolder) droped.getTag()).item;

                                        GridView parent = (GridView) droped.getParent();
                                        DragGridAdapter adapter = (DragGridAdapter) parent.getAdapter();
                                        List<GridItem> items = adapter.getItems();

                                        View target = v;
                                        GridItem targetItem = ((DragGridItemHolder) target.getTag()).item;
                                        int index = items.indexOf(targetItem);
                                        items.remove(dropItem);
                                        items.add(index, dropItem);
                                        adapter.notifyDataSetChanged();
                                    }
                                    break;
                                case DragEvent.ACTION_DRAG_ENDED:
                                    v.setBackgroundResource(R.drawable.shape_image_view_small_gallery_unselected);
                                    break;
                                default:
                                    result = false;
                                    break;
                                }
                                return result;
                            }
                        });
                    }

                    int relativePosition = position - parent.getFirstVisiblePosition();


                    View target = (View) parent.getChildAt(relativePosition);

                    DragGridItemHolder holder = (DragGridItemHolder) target.getTag();
                    GridItem currentItem = holder.item;
                    String text = currentItem.getFile().getAbsolutePath();

                    ClipData data = ClipData.newPlainText("DragData", text);
                    target.startDrag(data, new View.DragShadowBuilder(target), target, 0);
                }
            }
            return false;

and DragGridAdapter

public class DragGridAdapter extends BaseAdapter{
private Context context;
private List<GridItem> items;

public DragGridAdapter(List<GridItem> items, Context context){
    this.context = context;
    this.items = items;
}

@Override
public int getCount() {
    return items.size();
}

@Override
public Object getItem(int position) {
    return items.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    DragGridItemHolder holder;
    if (convertView == null) {
        holder = new DragGridItemHolder();

        ImageView img = new ImageView(context);
        holder.image = img;
        convertView = img;
        convertView.setTag(holder);
    } else {
        holder = (DragGridItemHolder) convertView.getTag();
    }
    holder.item = items.get(position);
    holder.image.setImageBitmap(items.get(position).getBitmap());
    return convertView;
}

public List<GridItem> getItems() {
    return items;
}

I hope it helps to you

Solution 2

My version for drag and drop grid view https://github.com/askerov/DynamicGrid.
It's extends original GridView, supports drag and drop to reorder items, auto-scroll if drag out of screen. It's completely functional on 3.0+ api, but supports 2.2 and 2.3 with limitations (no animations).

Solution 3

Have a look at thquinn's DraggableGridView, This was developed targeting Android 2.2 (API level 8). Hope this helps someone :)

Solution 4

Using the drag-n-drop framework, instead that cycling the childs and setting the draglistener, I use as a grid item layout container, a DragableLinearLayout that extends the LinearLayout and implements the onDragEvent(DragEvent) method.

So you can fill your grid with the adapter as usual and most of the drag and drop code is on the onDragEvent of DragableLinearLayout

public class DragableLinearLayout extends LinearLayout {


    public DragableLinearLayout(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);

    }

    public DragableLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    public DragableLinearLayout(Context context) {
        super(context);

    }

    @Override
    public boolean onDragEvent(DragEvent event) {
        //in wich grid item am I?
        GridView parent = (GridView) getParent();
        Object item = parent.getAdapter().getItem(
                parent.getPositionForView(this));
            //if you need the database id of your item...
        Cursor cur = (Cursor) item;
        long l_id = cur.getLong(cur.getColumnIndex("youritemid"));

        switch (event.getAction()) {
        case DragEvent.ACTION_DRAG_STARTED:

            return true;
        case DragEvent.ACTION_DRAG_ENTERED:

            setBackgroundColor(Color.GREEN);
            invalidate();
            return true;
        case DragEvent.ACTION_DRAG_EXITED:
            setBackgroundColor(Color.WHITE);
            invalidate();
            return false;
        case DragEvent.ACTION_DROP:
ClipData cd = event.getClipData();
            long l_id_start = Long.valueOf(cd.getItemAt(0).getText()
                    .toString());
            //
            Toast.makeText(getContext(), "DROP FROM " + l_id_start
                    + " TO " + l_id, Toast.LENGTH_LONG);
            //do your stuff  
                    ........
                    //the db requery will be on the onDragEvent.drop of the container
                    //see the listener


            return false;
        case DragEvent.ACTION_DRAG_ENDED:
            setBackgroundColor(Color.WHITE);
            invalidate();
            //
            return false;

        }

        return true;

    }


}



private View.OnDragListener listenerOnDragEvent = new View.OnDragListener() {

    public boolean onDrag(View v, DragEvent event) {
        // Defines a variable to store the action type for the incoming
        // event
        final int action = event.getAction();
        switch (action) {

        case DragEvent.ACTION_DROP:

            // REQUERY
            updateDbView();
            return false;
            // break;

        }
        return true;
    }
};

Solution 5

Google recently released a few code labs a few months back. https://codelabs.developers.google.com/codelabs/android-training-adaptive-layouts/index.html?index=..%2F..%2Fandroid-training#0

You can check the solution to it here https://github.com/google-developer-training/android-fundamentals-apps-v2/tree/master/MaterialMe-Resource

They make grid layout with movable cards that can be dragged and dropped anywhere in the layout using the itemTouchHandler.

The more detailed code on how to do the drag and drop is here You need to look into the Task 3: Make your CardView swipeable, movable, and clickable section

Share:
37,928
Admin
Author by

Admin

Updated on April 20, 2020

Comments

  • Admin
    Admin about 4 years

    I have a GridView in an application I am working on. I would like to be able to reorder the items in the GridView via drag-and-drop. I have found lots of help for ListViews but nothing on GridViews. I want to achieve behaviour like in this launcher app http://www.youtube.com/watch?v=u5LISE8BU_E&t=5m30s. Any ideas?

  • Ashish Dwivedi
    Ashish Dwivedi about 12 years
    View.OnDragListener is the part of Android-3.0, Above code is not working
  • Luciano
    Luciano over 11 years
    thnx for the example.. I got only got one bug.. The first time i drag a item over other items in the gridview, the imageview sources of the items are lost. When i drop it the sources wil be fixed.. After the first drag and drop of a activity everything works perfectly.. Any idea for the strange behaviour of this?
  • Dmytro Boichenko
    Dmytro Boichenko over 11 years
    Sorry, but I don't have answer for your question. Maybe it is a bug on your's device
  • Abx
    Abx about 11 years
    @Dmitriy_Boichenko .I like your code but it would be even more better if you give the code for DragGridItemHolder
  • Dmytro Boichenko
    Dmytro Boichenko about 11 years
    @Abhilash Unfortunatelly I don't have this code today. But as I remember it's simple. Please consider standard android's viewholder pattern
  • Abx
    Abx about 11 years
    @Dmitriy_Boichenko ,thanks for this reply to my late comment,I got it now ,it was just a view holder pattern afterall,missed that point entirely .
  • Dmytro Boichenko
    Dmytro Boichenko about 11 years
    This is cool solution. But it don't have any scroll listeners. So if you have a lot of pictures you can take Out Of Memory Error
  • Michał Klimczak
    Michał Klimczak almost 11 years
    It's not an AdapterView, so no view recycling is implemented
  • Pops
    Pops almost 11 years
    Thank you for taking the time to edit, but you seem to have missed the point a bit. This is still basically a link-only answer; such answers are discouraged. There are two main reasons for this: it's usually much more helpful to answer users' specific issues directly, and even links to good resources sometimes go bad. Please see this meta post for more detail.
  • Milan Delvadia
    Milan Delvadia over 10 years
    in the above library, I am not able to scroll in vertical direction when i'm dragging... any other options??
  • Andrei Buneyeu
    Andrei Buneyeu over 10 years
    Yeah, you should a bit customize it if you want scrolling. Try to implement ScrollView with DragDropGrid (not PagedDragDropGrid) inside, it helped me. Sorry, I have no time right now to find exact solution
  • Prateek
    Prateek almost 10 years
    Alex, your grid is not working well for two columns, specially while dragging from bottom to top. Can you please help.
  • user1940676
    user1940676 almost 10 years
    but how do you make it draggable only after a long click on the gridview item