web-dev-qa-db-fra.com

Android Afficher la liste Tri par glisser-déposer

J'ai une liste d'enregistrements dans une listview que je veux que l'utilisateur puisse trier de nouveau en utilisant une méthode de glisser-déposer. J'ai vu cela implémenté dans d'autres applications, mais je n'ai pas trouvé de tutoriel pour cela. Ce doit être quelque chose dont les autres ont également besoin. Quelqu'un peut-il m'indiquer un code pour le faire?

130
miannelle

J'y travaille depuis un certain temps maintenant. Difficile de bien faire les choses, et je ne prétends pas le faire, mais j'en suis satisfait jusqu'à présent. Mon code et plusieurs démos peuvent être trouvés à

Son utilisation est très similaire à TouchInterceptor (sur laquelle le code est basé), bien que des modifications importantes aient été apportées à la mise en œuvre.

DragSortListView permet un défilement régulier et prévisible lors du déplacement et de la réorganisation des éléments. Les shuffles d’éléments sont beaucoup plus compatibles avec la position de l’élément glissant/flottant. Les éléments de liste à hauteur hétérogène sont pris en charge. Le défilement par défilement est personnalisable (je montre un défilement rapide dans une longue liste - ce n’est pas une application qui vous vient à l’esprit). Les en-têtes/pieds de page sont respectés. etc.?? Regarde.

85
heycosmo

Ajoute cette réponse à l'intention de ceux qui Google sur ce sujet ..

Il y avait un épisode de DevBytes ( ListView Cell Dragging and Rearranging ) récemment qui explique comment faire cela

Vous pouvez le trouver ici aussi l'exemple de code est disponible ici .

En gros, ce code crée un dynamic listview par l’extension de listview qui prend en charge le déplacement et l’échange de cellules. Pour que vous puissiez utiliser le DynamicListView au lieu de votre ListView de base, vous avez implémenté une vue liste avec glisser-déposer.

18
Arun C

Maintenant, c'est assez facile à implémenter pour RecyclerView avec ItemTouchHelper . Remplacez juste la méthode onMove de ItemTouchHelper.Callback:

 @Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
    mMovieAdapter.swap(viewHolder.getAdapterPosition(), target.getAdapterPosition());
    return true;
}

Vous pouvez trouver un bon didacticiel à ce sujet sur medium.com: glisser-glisser avec RecyclerView

16
birdy

La bibliothèque DragListView fait cela vraiment bien avec un support très agréable pour les animations personnalisées telles que les animations d'élévation. Il est également maintenu et mis à jour régulièrement.

Voici comment vous l'utilisez:

1: Ajoute la bibliothèque à classer en premier

dependencies {
    compile 'com.github.woxthebox:draglistview:1.2.1'
}

2: Ajouter une liste à partir de xml

<com.woxthebox.draglistview.DragListView
    Android:id="@+id/draglistview"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"/>

3: Définir l'auditeur glisser

mDragListView.setDragListListener(new DragListView.DragListListener() {
    @Override
    public void onItemDragStarted(int position) {
    }

    @Override
    public void onItemDragEnded(int fromPosition, int toPosition) {
    }
});

4: Créer un adaptateur remplacé par DragItemAdapter

public class ItemAdapter extends DragItemAdapter<Pair<Long, String>, ItemAdapter.ViewHolder>
    public ItemAdapter(ArrayList<Pair<Long, String>> list, int layoutId, int grabHandleId, boolean dragOnLongPress) {
        super(dragOnLongPress);
        mLayoutId = layoutId;
        mGrabHandleId = grabHandleId;
        setHasStableIds(true);
        setItemList(list);
}

5: implémenter un viewholder qui s'étend de DragItemAdapter.ViewHolder

public class ViewHolder extends DragItemAdapter.ViewHolder {
    public TextView mText;

    public ViewHolder(final View itemView) {
        super(itemView, mGrabHandleId);
        mText = (TextView) itemView.findViewById(R.id.text);
    }

    @Override
    public void onItemClicked(View view) {
    }

    @Override
    public boolean onItemLongClicked(View view) {
        return true;
    }
}

Pour des informations plus détaillées, allez à https://github.com/woxblom/DragListView

5
Wox

J'ai trouvé DragSortListView a bien fonctionné, bien que le démarrer aurait pu être plus facile. Voici un bref tutoriel sur son utilisation dans Android Studio avec une liste en mémoire):

  1. Ajoutez ceci au build.gradle dépendances pour votre application:

    compile 'asia.ivity.Android:drag-sort-listview:1.0' // Corresponds to release 0.6.1
    
  2. Créez une ressource pour l'ID de la poignée de glissement en créant ou en ajoutant à values/ids.xml:

    <resources>
        ... possibly other resources ...
        <item type="id" name="drag_handle" />
    </resources>
    
  3. Créez une mise en page pour un élément de liste qui inclut votre image préférée de la poignée de glissement et affectez son ID à celui que vous avez créé à l'étape 2 (par exemple, drag_handle).

  4. Créez une mise en page DragSortListView, à peu près comme ceci:

    <com.mobeta.Android.dslv.DragSortListView
        xmlns:Android="http://schemas.Android.com/apk/res/Android"
        xmlns:dslv="http://schemas.Android.com/apk/res-auto"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        dslv:drag_handle_id="@id/drag_handle"
        dslv:float_background_color="@Android:color/background_light"/>
    
  5. Définissez un dérivé ArrayAdapter avec un remplacement getView qui restitue la vue de votre élément de liste.

        final ArrayAdapter<MyItem> itemAdapter = new ArrayAdapter<MyItem>(this, R.layout.my_item, R.id.my_item_name, items) { // The third parameter works around ugly Android legacy. http://stackoverflow.com/a/18529511/145173
            @Override public View getView(int position, View convertView, ViewGroup parent) {
                View view = super.getView(position, convertView, parent);
                MyItem item = getItem(position);
                ((TextView) view.findViewById(R.id.my_item_name)).setText(item.getName());
                // ... Fill in other views ...
                return view;
            }
        };
    
        dragSortListView.setAdapter(itemAdapter);
    
  6. Définissez un écouteur de dépôt qui réorganise les éléments au fur et à mesure qu'ils sont déposés.

        dragSortListView.setDropListener(new DragSortListView.DropListener() {
            @Override public void drop(int from, int to) {
                MyItem movedItem = items.get(from);
                items.remove(from);
                if (from > to) --from;
                items.add(to, movedItem);
                itemAdapter.notifyDataSetChanged();
            }
        });
    
5
Edward Brey

Je suis récemment tombé sur ce grand Gist qui donne une implémentation fonctionnelle d’un tri par glisser ListView, sans aucune dépendance externe.


En gros, cela consiste à créer votre adaptateur personnalisé en étendant ArrayAdapter en tant que classe interne à l'activité contenant votre ListView. Sur cet adaptateur, on place ensuite un onTouchListener dans votre liste d'éléments qui signaleront le début du glissement.

Dans ce Gist, ils définissent l'auditeur sur une partie spécifique de la présentation de l'élément de liste (le "descripteur" de l'élément), de sorte que l'utilisateur ne le déplace pas accidentellement en appuyant sur une partie quelconque de celui-ci. Personnellement, j’ai préféré utiliser un onLongClickListener à la 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 au ListView, qui vérifie si un élément est en train d'être déplacé, gère la permutation 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 glisser:

public void startDrag(String string) {
    mPosition = -1;
    mSortable = true;
    mDragString = string;
    mAdapter.notifyDataSetChanged();
}

public void stopDrag() {
    mPosition = -1;
    mSortable = false;
    mDragString = null;
    mAdapter.notifyDataSetChanged();
}
2
DarkCygnus