Visualizzazione elenco Android Trascinamento selezione


132

Ho un elenco di record in una visualizzazione elenco che desidero che l'utente possa riordinare utilizzando un metodo di trascinamento della selezione. L'ho visto implementato in altre app, ma non ho trovato un tutorial per questo. Deve essere qualcosa di cui anche gli altri hanno bisogno. Qualcuno può indicarmi un po 'di codice per farlo?


1
Ho trovato questo tutorial che potrebbe aiutare a creare una visualizzazione elenco ordinabile . Non l'ho ancora testato, ma il video sembra promettente
Alex,

@Arkde non scherzo, non hanno ancora accettato una risposta a questa domanda, anni dopo.
ArtOfWarfare il

@ArtOfWarfare Immagino che si debba considerare che qualcosa di spiacevole potrebbe essere accaduto al richiedente ... non consentire ulteriori attività.
heycosmo,

1
@heycosmo È possibile ... in base al loro profilo SO, miannelle ha visitato l'ultima volta un mese dopo aver posto la domanda. Inoltre, ottimo lavoro sul DSLV ... Ho apportato alcune modifiche per consentire cose come un doppio tocco per duplicare gli elementi e cambiare l'ombra dell'oggetto mentre viene trascinato (i miei oggetti hanno ciascuno il loro numero di riga su di essi, quindi io fatto in modo che gli aggiornamenti del numero di riga possano essere aggiornati man mano che vengono trascinati.) Sono un po 'semplicemente hackerati, molto meno eleganti di tutto il resto della classe, quindi perché non ho inviato le modifiche a GitHub.
ArtOfWarfare il

github.com/bauerca/drag-sort-listview lo sto usando ed è possibile trascinare un ROW su LongClick di Listview?
Achin,

Risposte:


85

Ci sto lavorando da un po 'di tempo ormai. Difficile da ottenere, e non pretendo di farlo, ma sono contento finora. Il mio codice e diverse demo sono disponibili all'indirizzo

Il suo utilizzo è molto simile al TouchInterceptor (su cui si basa il codice), sebbene siano state apportate modifiche significative all'implementazione.

DragSortListView ha uno scorrimento fluido e prevedibile durante il trascinamento e lo shuffle degli elementi. I mescolamenti degli oggetti sono molto più coerenti con la posizione dell'oggetto trascinante / mobile. Sono supportate voci di elenco ad altezza eterogenea. Il trascinamento del trascinamento è personalizzabile (dimostrerò lo scorrimento rapido del trascinamento attraverso un lungo elenco --- non che mi venga in mente un'applicazione). Le intestazioni / i piè di pagina sono rispettate. eccetera.?? Guarda.


3
La tua soluzione funziona come un fascino. Molto meglio degli altri. Qual è la licenza del tuo codice sorgente? Apache 2.0?
Dariusz Bacinski,

1
@heycosmo Ho alcuni problemi durante la creazione di un layout nella mia app usando le viste fornite nella demo. Errore di diversi spazi dei nomi, potresti forse fare un piccolo post sul blog su come utilizzare il codice fornito?
daniel_c05,

Esiste la possibilità di modificare il codice in modo che gli oggetti vengano ordinati non solo al momento del rilascio mentre si trascina l'oggetto sopra di essi?
Alex Semeniuk,

@heycosmo Puoi rendere accessibile il tuo repository GitHub? Sembra essere offline ...
sdasdadas,

8
Il repo bauerca non è più mantenuto. Questo fork è più attivo: github.com/JayH5/drag-sort-listview
ecdpalma

21

Ora è abbastanza facile da implementare RecyclerViewcon ItemTouchHelper . Basta sostituire il onMovemetodo da ItemTouchHelper.Callback:

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

Un tutorial abbastanza buono su questo può essere trovato su medium.com: trascina e scorri con RecyclerView


18

Sto aggiungendo questa risposta ai fini di chi google su questo ..

Recentemente si è verificato un episodio di DevBytes ( trascinamento e riorganizzazione delle celle di ListView ) che spiega come farlo

Puoi trovarlo qui anche il codice di esempio è disponibile qui .

Ciò che questo codice fondamentalmente fa è che crea dynamic listviewun'estensione listviewche supporta il trascinamento e lo scambio di celle. In modo che tu possa usare DynamicListViewinvece il tuo base ListView e basta che hai implementato un ListView con Drag and Drop.


1
Quando si utilizza l'implementazione di DevBytes, tenere presente che l'adattatore e la poltiglia di DynamicListView condividono la stessa istanza se gli oggetti array. Altrimenti l'implementazione non funzionerà. Questo non è un problema per gli elenchi statici, ma può essere una sfida con
Loaders

Ho provato l'esempio su una versione 5.0 di Android corrente. Ora ha qualche problema ...
Torsten B,

@TCA Sì, anche io ho avuto problemi con la 5.0. Per favore aiuto.
Manu,

6

La libreria DragListView lo fa davvero bene con un ottimo supporto per animazioni personalizzate come animazioni di elevazione. Inoltre è ancora mantenuto e aggiornato su base regolare.

Ecco come lo usi:

1: aggiungi prima la lib al gradle

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

2: Aggiungi elenco da XML

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

3: imposta il listener di trascinamento

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

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

4: creare un adattatore sovrascritto da 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: implementare un viewholder che si estende da 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;
    }
}

Per informazioni più dettagliate, visitare https://github.com/woxblom/DragListView


5

Ho scoperto che DragSortListView ha funzionato bene, anche se iniziare su di esso avrebbe potuto essere più facile. Ecco un breve tutorial su come usarlo in Android Studio con un elenco in memoria:

  1. Aggiungi questo alle build.gradledipendenze per la tua app:

    compile 'asia.ivity.android:drag-sort-listview:1.0' // Corresponds to release 0.6.1
  2. Creare una risorsa per l'ID handle di trascinamento creando o aggiungendo a values/ids.xml:

    <resources>
        ... possibly other resources ...
        <item type="id" name="drag_handle" />
    </resources>
  3. Crea un layout per un elemento dell'elenco che include l'immagine della maniglia di trascinamento preferita e assegna il suo ID all'ID creato nel passaggio 2 (ad es drag_handle.).

  4. Crea un layout DragSortListView, in questo modo:

    <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. Imposta una ArrayAdapterderivata con una getViewsostituzione che renda la visualizzazione della tua voce di elenco.

        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. Impostare un listener di rilascio che riorganizza gli elementi man mano che vengono rilasciati.

        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();
            }
        });

3

Di recente mi sono imbattuto in questo grande Gist che offre un'implementazione funzionante di una sorta di trascinamento ListView, senza necessità di dipendenze esterne.


Fondamentalmente si tratta di creare il tuo adattatore personalizzato che si estende ArrayAdaptercome classe interna all'attività che contiene il tuo ListView. Su questo adattatore uno quindi imposta un onTouchListenerai tuoi elementi di elenco che segnalerà l'inizio del trascinamento.

In quel Gist hanno impostato l'ascoltatore su una parte specifica del layout dell'elemento della lista (la "maniglia" dell'elemento), in modo da non spostarlo accidentalmente premendo qualsiasi parte di esso. Personalmente, ho preferito andare con un onLongClickListenerinvece, ma spetta a te decidere. Ecco un estratto di quella 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;
    }
}

Ciò comporta anche l'aggiunta di un carattere onTouchListenera ListView, che verifica se un elemento viene trascinato, gestisce lo scambio e l'invalidazione e interrompe lo stato di trascinamento. Un estratto di quella 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;
    }
});

Infine, ecco come appaiono i metodi stopDrage startDrag, che gestiscono l'abilitazione e la disabilitazione del processo di trascinamento:

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

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

Mentre questa sembra essere una delle implementazioni più semplici, sembra male (le righe cambiano, in realtà non ha un aspetto), si sente male e rende impossibile scorrere un elenco che non si adatta allo schermo quasi impossibile (cambio costantemente le righe invece di scrolling).
Heinzlmaen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.