Tampilan Daftar Android Seret dan Jatuhkan sort

132

Saya memiliki daftar catatan dalam tampilan daftar yang saya ingin pengguna dapat mengurutkan ulang menggunakan metode drag and drop. Saya telah melihat ini diterapkan di aplikasi lain, tetapi saya belum menemukan tutorial untuk itu. Itu pasti sesuatu yang dibutuhkan orang lain juga. Adakah yang bisa mengarahkan saya ke beberapa kode untuk melakukan ini?

miannelle
sumber
1
Saya telah menemukan tutorial ini yang dapat membantu membuat tampilan daftar yang dapat diurutkan . Saya belum mengujinya tetapi videonya terlihat menjanjikan
Alex
@Arkde jangan bercanda, mereka masih belum menerima jawaban untuk pertanyaan ini, bertahun-tahun kemudian.
ArtOfWarfare
@ ArtOfWarfare Saya kira orang harus mempertimbangkan bahwa sesuatu yang malang bisa terjadi pada penanya ... melarang kegiatan lebih lanjut.
heycosmo
1
@heycosmo Mungkin saja ... menurut profil SO mereka, miannelle mengunjungi terakhir hanya sebulan setelah mengajukan pertanyaan. Juga, pekerjaan hebat pada DSLV ... Saya membuat beberapa modifikasi untuk memungkinkan hal-hal seperti ketuk dua kali untuk menggandakan item dan mengubah bayangan item saat diseret (item saya masing-masing memiliki nomor baris pada mereka, jadi saya membuatnya sehingga pembaruan nomor baris dapat diperbarui saat diseret.) Mereka semacam baru saja diretas, jauh lebih tidak elegan daripada yang lainnya di kelas, jadi mengapa saya belum mengirimkan perubahan ke GitHub.
ArtOfWarfare
github.com/bauerca/drag-sort-listview saya menggunakan ini dan apakah mungkin untuk menyeret ROW onLongClick of Listview?
Achin

Jawaban:

85

Saya telah mengerjakan ini selama beberapa waktu sekarang. Sulit untuk mendapatkan yang benar, dan saya tidak mengklaim saya lakukan, tapi saya senang dengan itu sejauh ini. Kode saya dan beberapa demo dapat ditemukan di

Penggunaannya sangat mirip dengan TouchInterceptor (yang menjadi basis kode), meskipun perubahan implementasi yang signifikan telah dibuat.

DragSortListView memiliki pengguliran yang halus dan dapat diprediksi sambil menyeret dan mengacak item. Mengocok item jauh lebih konsisten dengan posisi item menyeret / mengambang. Item daftar tinggi-heterogen didukung. Pengguliran seret dapat disesuaikan (saya mendemonstrasikan pengguliran seret cepat melalui daftar panjang --- bukan berarti suatu aplikasi masuk dalam pikiran). Header / Footer dihormati. dll ?? Lihatlah.

heycosmo
sumber
3
Solusi Anda bekerja seperti pesona. Jauh lebih baik daripada yang lain. Apa lisensi kode sumber Anda? Apache 2.0?
Dariusz Bacinski
1
@heycosmo Saya punya beberapa masalah saat membuat tata letak di aplikasi saya menggunakan tampilan yang disediakan pada demo. Beberapa kesalahan namespaces, bisakah Anda melakukan blogpost kecil tentang cara menggunakan kode yang Anda berikan?
daniel_c05
Apakah ada kemungkinan untuk mengubah kode sedemikian rupa sehingga barang-barang disortir tidak hanya pada drop by saat Anda menyeret item Anda di atasnya?
Alex Semeniuk
@heycosmo Bisakah Anda membuat repositori GitHub Anda dapat diakses? Tampaknya sedang offline ...
sdasdadas
8
Repo bauerca tidak lagi dipertahankan. Garpu ini lebih aktif: github.com/JayH5/drag-sort-listview
ecdpalma
21

Sekarang cukup mudah untuk diterapkan RecyclerViewdengan ItemTouchHelper . Cukup timpa onMovemetode dari ItemTouchHelper.Callback:

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

Tutorial yang cukup bagus tentang ini dapat ditemukan di medium.com: Seret dan Gesek dengan RecyclerView

birdy
sumber
18

Saya menambahkan jawaban ini untuk keperluan mereka yang mencari tahu tentang ini ..

Ada sebuah episode DevBytes ( ListView Cell Dragging dan Mengatur Ulang ) baru-baru ini yang menjelaskan bagaimana melakukan ini

Anda dapat menemukannya di sini juga kode sampel tersedia di sini .

Apa yang pada dasarnya dilakukan oleh kode ini adalah kode itu dibuat dynamic listviewdengan ekstensi listviewyang mendukung seret dan swapping sel. Sehingga Anda dapat menggunakan DynamicListViewbukan dasar Anda ListView dan hanya itu Anda telah menerapkan ListView dengan Drag dan Drop.

Arun C
sumber
1
Saat menggunakan implementasi DevBytes perlu diingat bahwa adaptor Anda dan DynamicListView harus berbagi instance yang sama jika objek array. Kalau tidak, implementasi tidak akan berhasil. Ini bukan masalah untuk daftar statis tetapi mungkin menjadi tantangan dengan Loader
AAverin
Saya mencoba contoh pada versi Android 5.0 saat ini. Ini memiliki beberapa masalah sekarang ...
Torsten B
@ TCA Ya, saya juga punya masalah di 5.0. Tolong bantu.
Manu
6

Lib DragListView melakukan ini dengan sangat rapi dengan dukungan yang sangat bagus untuk animasi khusus seperti animasi elevasi. Itu juga masih dipertahankan dan diperbarui secara teratur.

Inilah cara Anda menggunakannya:

1: Tambahkan Lib untuk gradle pertama

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

2: Tambahkan daftar dari xml

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

3: Atur pendengar seret

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

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

4: Buat adaptor yang diganti dari 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: Menerapkan viewholder yang memanjang dari 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;
    }
}

Untuk info lebih rinci, kunjungi https://github.com/woxblom/DragListView

Wox
sumber
5

Saya menemukan DragSortListView bekerja dengan baik, meskipun memulainya bisa lebih mudah. Berikut tutorial singkat tentang cara menggunakannya di Android Studio dengan daftar dalam memori:

  1. Tambahkan ini ke build.gradledependensi untuk aplikasi Anda:

    compile 'asia.ivity.android:drag-sort-listview:1.0' // Corresponds to release 0.6.1
  2. Buat sumber daya untuk drag handle ID dengan membuat atau menambahkan ke values/ids.xml:

    <resources>
        ... possibly other resources ...
        <item type="id" name="drag_handle" />
    </resources>
  3. Buat tata letak untuk item daftar yang menyertakan gambar pegangan seret favorit Anda, dan berikan ID-nya ke ID yang Anda buat pada langkah 2 (mis drag_handle.).

  4. Buat tata letak DragSortListView, sesuatu seperti ini:

    <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. Tetapkan ArrayAdapterturunan dengan getViewpenggantian yang membuat tampilan item daftar Anda.

        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. Tetapkan pendengar jatuh yang mengatur ulang item saat dijatuhkan.

        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();
            }
        });
Edward Brey
sumber
3

Saya baru-baru ini menemukan inti besar ini yang memberikan implementasi yang baik dari jenis drag ListView, tanpa ketergantungan eksternal diperlukan.


Pada dasarnya ini terdiri dari menciptakan Adaptor kustom Anda yang diperluas ArrayAdaptersebagai kelas dalam untuk aktivitas yang berisi Anda ListView. Pada adaptor ini, satu set onTouchListenerke Item Daftar Anda yang akan menandakan awal dari hambatan.

Dalam Gist itu mereka mengatur pendengar ke bagian tertentu dari tata letak Item Daftar ("pegangan" item), jadi orang tidak sengaja memindahkannya dengan menekan bagian mana pun darinya. Secara pribadi, saya lebih memilih untuk pergi dengan onLongClickListenergantinya, tetapi itu terserah Anda untuk memutuskan. Berikut kutipan dari bagian itu:

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

Ini juga melibatkan penambahan onTouchListenerke ListView, yang memeriksa apakah suatu item diseret, menangani pertukaran dan pembatalan, dan menghentikan status seret. Kutipan dari bagian itu:

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

Akhirnya, berikut adalah bagaimana stopDragdan startDragmetode yang terlihat, yang menangani mengaktifkan dan menonaktifkan proses seret:

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

public void stopDrag() {
    mPosition = -1;
    mSortable = false;
    mDragString = null;
    mAdapter.notifyDataSetChanged();
}
DarkCygnus
sumber
Meskipun ini tampaknya menjadi salah satu implementasi termudah, itu terlihat buruk (baris hanya beralih, sebenarnya tidak ada tampilan), rasanya buruk dan membuat bergulir melalui daftar yang tidak sesuai dengan layar hampir tidak mungkin (saya terus-menerus mengganti baris daripada bergulir).
Heinzlmaen