简体   繁体   中英

swap items in a Gridview trouble with the dropped position in Android

i have been trying to swap items in a Grid view, and this is where i got:

xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/parent_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <GridView
        android:id="@+id/grid_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:horizontalSpacing="10dip"
        android:numColumns="4"
        android:verticalSpacing="10dip" />

</RelativeLayout>

main activity class:

public class MainActivity extends Activity implements OnDragListener,
        OnItemLongClickListener {

    ArrayList drawables;

    GridView gridView;
    private BaseAdapter adapter;
    private int draggedIndex = -1;
    private int droppedIndex = -1;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        drawables = new ArrayList();
        drawables.add(R.drawable.ic_launcher);
        drawables.add(R.drawable.ic_launcher1);
        drawables.add(R.drawable.ic_launcher2);
        drawables.add(R.drawable.ic_launcher);
        drawables.add(R.drawable.ic_launcher);
        drawables.add(R.drawable.ic_launcher);
        drawables.add(R.drawable.ic_launcher);
        drawables.add(R.drawable.ic_launcher);
        gridView = (GridView) findViewById(R.id.grid_view);
        gridView.setOnItemLongClickListener(MainActivity.this);
        gridView.setAdapter(adapter = new BaseAdapter() {

            @Override
            // Get a View that displays the data at the specified position in
            // the data set.
            public View getView(int position, View convertView,
                    ViewGroup gridView) {
                // try to reuse the views.
                ImageView view = (ImageView) convertView;
                // if convert view is null then create a new instance else reuse
                // it
                if (view == null) {
                    view = new ImageView(MainActivity.this);
                }
                view.setImageResource((Integer) drawables.get(position));
                view.setTag(String.valueOf(position));
                return view;
            }

            @Override
            // Get the row id associated with the specified position in the
            // list.
            public long getItemId(int position) {
                return position;
            }

            @Override
            // Get the data item associated with the specified position in the
            // data set.
            public Object getItem(int position) {
                return drawables.get(position);
            }

            @Override
            // How many items are in the data set represented by this Adapter.
            public int getCount() {
                return drawables.size();
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onDrag(View view, DragEvent dragEvent) {
        switch (dragEvent.getAction()) {
        case DragEvent.ACTION_DRAG_STARTED:
            // Ignore this event
             return true;
        case DragEvent.ACTION_DRAG_ENTERED:
            // Ignore this event
            return true;
        case DragEvent.ACTION_DRAG_EXITED:
            // Ignore this event
            return true;
        case DragEvent.ACTION_DRAG_LOCATION:
            // Ignore this event
            return true;
        case DragEvent.ACTION_DROP:
            // Dropped inside a new view\
                adapter.notifyDataSetChanged();
                ImageView v2 = (ImageView)view.getParent();
                final int position1 = gridView.getPositionForView(v2);
                if (position1 >= 0) 
                { 
                    final long droppedIndex = gridView.getAdapter().getItemId(position1); 
                }
                Object item1 = gridView.getAdapter().getItem(draggedIndex);
                Object item2 = gridView.getAdapter().getItem(droppedIndex);
                drawables.remove(draggedIndex);
                drawables.remove(droppedIndex);
                drawables.add(droppedIndex,item1);
                drawables.add(draggedIndex,item2);
                draggedIndex = -1;
                droppedIndex = -1;
                adapter.notifyDataSetChanged();
        case DragEvent.ACTION_DRAG_ENDED:
           //
            view.setOnDragListener(null);
            return true;

         }
        return false;
    }

    @Override
    public boolean onItemLongClick(AdapterView gridView, View view,
            int position, long row) {
        ClipData.Item item = new ClipData.Item((String) view.getTag());
        ClipData clipData = new ClipData((CharSequence) view.getTag(),
                new String[] { ClipDescription.MIMETYPE_TEXT_PLAIN }, item);
        view.startDrag(clipData, new View.DragShadowBuilder(view), null, 0);
        view.setVisibility(View.INVISIBLE);
        draggedIndex = position;
        return true;
    }
}

my problem is in DragEvent.ACTION_DROP. I works like this: I drag one item and, when drop it in another place, the item disappears. And that is all.

Supposedly, first retrieve both positions: the position of the item dragged (draggedIndex) and the position where the item is dropped (droppedIndex). After, i remove both items and add them to the array again in the opposite positions (the item dragged goes to droppedIndex and the other goes to the draggedIndex, so they are exchanged/swaped)

I wonder if it is a good way to do this, or if i made any mistakes trying to retrieve the dropped position (droppedIndex). any ideas?

Before removing the item , just add the item into dropped position. Then remove the corresponding item by incrementing the dropped position by 1.

case DragEvent.ACTION_DROP:

....
drawables.add(droppedIndex,item1);
            drawables.add(draggedIndex+1,item2);
 drawables.remove(draggedIndex+2);
            drawables.remove(droppedIndex+2);
....

hope this will help you.

I took a slightly different approach to get the dropped index. For an ACTION_DROP event, getX() and getY() return the X and Y position of the drag point at the moment of the drop, using the coordinate system of the View that received the drop (ie the gridview).

float dropX = event.getX();
float dropY = event.getY();

Once you have the x and y co-ordinates you can calculate the corresponding row and column in your grid view, and then use something like the following to get the index of the object in your data array (I have a 4 x 4 grid):

index = row * 4 + column;

Finally, I'm using an array list (targetDrawables) to hold the references to my gridview contents, so to reorder use:

targetDrawables.remove(draggedIndex);
targetDrawables.add(droppedIndex, draggedContents);

//  Invalidate the view to force a redraw of the Grid View

imageAdapter.notifyDataSetChanged();

Your code is fine; just replace

Object item1 = gridView.getAdapter().getItem(draggedIndex);
Object item2 = gridView.getAdapter().getItem(droppedIndex);
drawables.remove(draggedIndex);
drawables.remove(droppedIndex);
drawables.add(droppedIndex,item1);
drawables.add(draggedIndex,item2);

with

Collections.swap(drawables, draggedIndex, droppedIndex);

It swaps position of list and now it works!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM