Android GridView reorder elements via Drag and Drop

我只是一个虾纸丫 提交于 2020-01-09 12:19:56

问题


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?


回答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




回答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).




回答3:


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




回答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;
    }
};



回答5:


Not easy to provide a short answer on this, as there are hundreds of lines of code involved: you will need to intercept start of dragging action, usually on onLongClick, hide the view that initiated the action, show an overlay that can be moved around while the user is still in touch down action, and finally do the changes on touch up . The best way to go is to extend the standard GridView in android.widget . The result looks like this:

Here is a youtube video demo that you might find useful: http://www.youtube.com/watch?v=m4yktX3SWSs&feature=youtu.be

I also put together a more detailed answer in an article on my blog, you might find it useful as it comes with a complete source code example. The link is: http://www.pocketmagic.net/2013/11/complex-android-gridview-with-drag-and-drop-functionality/




回答6:


I recently found a solution on which its author spent quite some time here http://blahti.wordpress.com/2012/03/03/improved-drag-drop-for-gridview/ There are 4 previous related blog posts explaining what is going on in more detail there.




回答7:


Probably PagedDragDropGrid project is what you need: https://github.com/mrKlar/PagedDragDropGrid

It provides custom ViewGroup (similar to GridView) with feature of smooth reordering (exactly like in your video). Probably it'll require a bit of customizations, but it's worth.

Hope it'll help.




回答8:


Here's a library from h6ah4i that takes advantage of the Recycler Views to offer a drag and drop gridview with reorder capabilities.




回答9:


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



来源:https://stackoverflow.com/questions/7146639/android-gridview-reorder-elements-via-drag-and-drop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!