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;
}
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With