I recently stumbled upon this great Gist that gives a working implementation of a drag sort ListView, with no external dependencies needed.
Basically it consists on creating your custom Adapter extending ArrayAdapter as an inner class to the activity containing your ListView. On this adapter one then sets an onTouchListener to your List Items that will signal the start of the drag.
In that Gist they set the listener to a specific part of the layout of the List Item (the "handle" of the item), so one does not accidentally move it by pressing any part of it. Personally, I preferred to go with an onLongClickListener instead, but that is up to you to decide. Here an excerpt of that part:
public class MyArrayAdapter extends ArrayAdapter {
private ArrayList mStrings = new ArrayList();
private LayoutInflater mInflater;
private int mLayout;
//constructor, clear, remove, add, insert...
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
View view = convertView;
//inflate, etc...
final String string = mStrings.get(position);
holder.title.setText(string);
// Here the listener is set specifically to the handle of the layout
holder.handle.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
startDrag(string);
return true;
}
return false;
}
});
// change color on dragging item and other things...
return view;
}
}
This also involves adding an onTouchListener to the ListView, which checks if an item is being dragged, handles the swapping and invalidation, and stops the drag state. An excerpt of that part:
mListView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
if (!mSortable) { return false; }
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
break;
}
case MotionEvent.ACTION_MOVE: {
// get positions
int position = mListView.pointToPosition((int) event.getX(),
(int) event.getY());
if (position < 0) {
break;
}
// check if it's time to swap
if (position != mPosition) {
mPosition = position;
mAdapter.remove(mDragString);
mAdapter.insert(mDragString, mPosition);
}
return true;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_OUTSIDE: {
//stop drag state
stopDrag();
return true;
}
}
return false;
}
});
Finally, here is how the stopDrag and startDrag methods look like, which handle the enabling and disabling of the drag process:
public void startDrag(String string) {
mPosition = -1;
mSortable = true;
mDragString = string;
mAdapter.notifyDataSetChanged();
}
public void stopDrag() {
mPosition = -1;
mSortable = false;
mDragString = null;
mAdapter.notifyDataSetChanged();
}