Недавно я наткнулся на этот замечательный Gist, который дает рабочую реализацию сортировки перетаскиванием ListView
без каких-либо внешних зависимостей.
По сути, он заключается в создании вашего собственного адаптера, расширяющегося ArrayAdapter
как внутренний класс до активности, содержащей ваш ListView
. Затем на этом адаптере устанавливается onTouchListener
элемент списка, который будет сигнализировать о начале перетаскивания.
В этом Gist они устанавливают слушателя на определенную часть макета элемента списка («дескриптор» элемента), поэтому его нельзя случайно переместить, нажав любую его часть. Лично я предпочел использовать onLongClickListener
вместо этого, но это решать вам. Вот отрывок из этой части:
public class MyArrayAdapter extends ArrayAdapter<String> {
private ArrayList<String> mStrings = new ArrayList<String>();
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;
}
}
Это также включает добавление onTouchListener
в ListView
, который проверяет, перетаскивается ли элемент, обрабатывает замену и недействительность, а также останавливает состояние перетаскивания. Отрывок из этой части:
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;
}
});
И, наконец, вот как stopDrag
и startDrag
методы похожи, что обрабатывать включение и выключение процесса перетаскивания:
public void startDrag(String string) {
mPosition = -1;
mSortable = true;
mDragString = string;
mAdapter.notifyDataSetChanged();
}
public void stopDrag() {
mPosition = -1;
mSortable = false;
mDragString = null;
mAdapter.notifyDataSetChanged();
}