Je suis récemment tombé sur ce grand Gist qui donne une implémentation fonctionnelle d'une sorte de drag ListView
, sans dépendances externes nécessaires.
Fondamentalement, il consiste à créer votre adaptateur personnalisé s'étendant en ArrayAdapter
tant que classe interne à l'activité contenant votre ListView
. Sur cet adaptateur, on définit ensuite un onTouchListener
sur vos éléments de liste qui signalera le début du glissement.
Dans ce Gist, ils définissent l'auditeur sur une partie spécifique de la mise en page de l'élément de liste (la "poignée" de l'élément), de sorte que l'on ne le déplace pas accidentellement en appuyant sur une partie de celui-ci. Personnellement, j'ai préféré aller avec un à la onLongClickListener
place, mais c'est à vous de décider. Voici un extrait de cette partie:
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;
}
}
Cela implique également l'ajout d'un onTouchListener
à ListView
, qui vérifie si un élément est déplacé, gère l'échange et l'invalidation et arrête l'état de glissement. Un extrait de cette partie:
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;
}
});
Enfin, voici à quoi ressemblent les méthodes stopDrag
et startDrag
, qui gèrent l'activation et la désactivation du processus de glissement:
public void startDrag(String string) {
mPosition = -1;
mSortable = true;
mDragString = string;
mAdapter.notifyDataSetChanged();
}
public void stopDrag() {
mPosition = -1;
mSortable = false;
mDragString = null;
mAdapter.notifyDataSetChanged();
}