Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android ListView Drag and Drop for Honeycomb and ICS "Error: Reporting drop result: false"

I have been trying to create a ListView which I can sort using drag and drop.

I have attempted to follow the Android guide here and some source code provided on Git over here. Also, I do not want to use the Music app example as I am trying to use the new tools given in Honeycomb and up.

So far I have been successful in creating the list and I can drag the items. Unfortunately when I drop the item onto the list I get the following error:

"I/ViewRoot(22739): Reporting drop result: false".

I have a suspicion that my drop listener is not created on the right item and thus the drop never gets called. Here is some source code, thank you so much for your help.

XML For the List:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/dropTarget"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
     android:layout_weight="1">
    <ListView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@android:id/list" >
    </ListView>
</LinearLayout>

My listView: I have not yet been able to get into "ACTION_DROP" event so that code is not tested. Just something I was working on. My main question is that I never get into ACTION_DROP.

public class procedureListView extends ListActivity {
    private ListView mListView = null;
    private ArrayAdapter<String> mArrayAdapter = null;
    private View layoutDropArea = null;

    public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.list);

          String[] countries = getResources().getStringArray(R.array.arrayOfStuff);
          mArrayAdapter = new ArrayAdapter<String>(this, R.layout.list_item, countries);
          setListAdapter(mArrayAdapter);

          mListView = getListView();
          mListView.setTextFilterEnabled(true);

          layoutDropArea = findViewById(R.id.dropTarget);

          setupDragDrop();
    }
    /**
     * Setup what to do when we drag list items
     */
    public void setupDragDrop(){
        mListView.setOnItemLongClickListener(new OnItemLongClickListener() {
            public boolean onItemLongClick(AdapterView<?> arg0, View v, int position, long arg3){
                String value = (String) ((TextView) v).getText();
                ClipData data = ClipData.newPlainText("procedure", value);
                v.startDrag(data, new mDragShadowBuilder(v), null, 0);          
                return true;
            }
        });
        myDragListener mDragListener = new myDragListener();
        //mListView.setOnDragListener(mDragListener);

        layoutDropArea.setOnDragListener(mDragListener);



    }
    protected class myDragListener implements OnDragListener{

        public boolean onDrag(View v, DragEvent event) {
            final int action = event.getAction();
            switch (action) {
                case DragEvent.ACTION_DRAG_ENTERED:
                    v.setBackgroundColor(Color.GRAY);
                    break;
                case DragEvent.ACTION_DRAG_EXITED:
                    v.setBackgroundColor(Color.TRANSPARENT);
                    break;
                case DragEvent.ACTION_DRAG_STARTED:
                    break;
                case DragEvent.ACTION_DRAG_LOCATION:
                    v.setVisibility(View.VISIBLE);
                // return processDragStarted(event);
                case DragEvent.ACTION_DROP:
                    v.setBackgroundColor(Color.TRANSPARENT);
                    int newPosition = mListView.getPositionForView(v);
                    if (newPosition != ListView.INVALID_POSITION)
                        return processDrop(event, newPosition);
                    else
                        return false;
            }
            return false;
        }

    }

    private boolean processDrop(DragEvent event, int newPosition) {
        ClipData data = event.getClipData();
        if (data != null) {
            if (data.getItemCount() > 0) {
                Item item = data.getItemAt(0);
                String value = item.toString();
                updateViewsAfterDropComplete(value, newPosition);
                return true;
            }
        }
        return false;
    }
    private void updateViewsAfterDropComplete(String listItem, int index) {
        Log.d("InsertItem", "Position: "+ index);
        mArrayAdapter.insert(listItem, index);
        mArrayAdapter.notifyDataSetChanged();
    }
    private boolean processDragStarted(DragEvent event) {
        ClipDescription clipDesc = event.getClipDescription();
        if (clipDesc != null) {
            return clipDesc.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN);
        }
        return false;
    }
}

Thank you so much for your help!

UPDATE:

I could not quite figure out why. But when I changed switch case to this, it seemed to work:

switch (action) {
                case DragEvent.ACTION_DRAG_ENTERED:
                    //v.setBackgroundColor(Color.GRAY);
                    return false;

                case DragEvent.ACTION_DRAG_EXITED:
                    //v.setBackgroundColor(Color.TRANSPARENT);
                    return true;

                case DragEvent.ACTION_DRAG_STARTED:
                    return true;

                case DragEvent.ACTION_DRAG_LOCATION:
                    //v.setVisibility(View.VISIBLE);
                    return false;
                // return processDragStarted(event);
                case DragEvent.ACTION_DROP:
                    v.setBackgroundColor(Color.TRANSPARENT);
                    int newPosition = mListView.pointToPosition((int)(event.getX()),(int) event.getY());
                    Log.d("Position", Integer.toString(newPosition));
                    if (newPosition != ListView.INVALID_POSITION)
                        return processDrop(event, newPosition);
                    else
                        return false;
                default:
                    return true;

            }
like image 285
AlexIIP Avatar asked May 23 '12 21:05

AlexIIP


1 Answers

Your update fixed the problem because you have to return true from onDrag when you get DragEvent.ACTION_DRAG_STARTED in order to continue receiving drag events to that listener. In your update you return true for this case, so you continue receiving drag events and the drop logic works correctly.

If you don't return true for the DragEvent.ACTION_DRAG_STARTED case, your listener won't get any other events except DragEvent.ACTION_DRAG_ENDED.

like image 176
ashughes Avatar answered Sep 18 '22 05:09

ashughes