Recentemente, deparei-me com este excelente Gist que fornece uma implementação funcional de uma classificação por arraste ListView
, sem dependências externas necessárias.
Basicamente, ele consiste em criar seu Adaptador customizado estendendo-se ArrayAdapter
como uma classe interna para a atividade que contém o seu ListView
. Nesse adaptador, um define um onTouchListener
para seus Itens da lista que sinalizará o início do arrasto.
Nesse Gist, eles definem o ouvinte para uma parte específica do layout do Item da lista (o "identificador" do item), para que não seja movido acidentalmente pressionando qualquer parte dele. Pessoalmente, preferi optar por um onLongClickListener
, mas isso depende de você decidir. Aqui um trecho dessa parte:
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;
}
}
Isso também envolve adicionar um onTouchListener
ao ListView
, que verifica se um item está sendo arrastado, manipula a troca e a invalidação e interrompe o estado do arrasto. Um trecho dessa parte:
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;
}
});
Por fim, eis a aparência dos métodos stopDrag
e startDrag
, que tratam da ativação e desativação do processo de arrastar:
public void startDrag(String string) {
mPosition = -1;
mSortable = true;
mDragString = string;
mAdapter.notifyDataSetChanged();
}
public void stopDrag() {
mPosition = -1;
mSortable = false;
mDragString = null;
mAdapter.notifyDataSetChanged();
}