Mam listę rekordów w widoku listy, którą chcę, aby użytkownik mógł ponownie posortować za pomocą metody przeciągnij i upuść. Widziałem to zaimplementowane w innych aplikacjach, ale nie znalazłem dla niego samouczka. To musi być coś, czego inni też potrzebują. Czy ktoś może wskazać mi jakiś kod do zrobienia tego?
132
Odpowiedzi:
Pracuję nad tym już od jakiegoś czasu. Trudno jest uzyskać rację i nie twierdzę, że tak, ale jak na razie jestem z tego zadowolony. Mój kod i kilka wersji demonstracyjnych można znaleźć pod adresem
Jego użycie jest bardzo podobne do TouchInterceptora (na którym oparty jest kod), chociaż wprowadzono znaczące zmiany implementacyjne.
DragSortListView zapewnia płynne i przewidywalne przewijanie podczas przeciągania i tasowania elementów. Tasowanie przedmiotów jest znacznie bardziej spójne z pozycją przeciąganego / unoszącego się przedmiotu. Obsługiwane są elementy listy o niejednorodnej wysokości. Przewijanie metodą przeciągania można dostosować (pokazuję szybkie przewijanie przeciąganiem po długiej liście - nie chodzi o aplikację). Nagłówki / stopki są przestrzegane. itp.?? Spójrz.
źródło
Teraz jest to dość łatwe do wykonania dla
RecyclerView
z ItemTouchHelper . Po prostu zastąponMove
metodę zItemTouchHelper.Callback
:@Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { mMovieAdapter.swap(viewHolder.getAdapterPosition(), target.getAdapterPosition()); return true; }
Całkiem dobry poradnik na ten temat można znaleźć na medium.com: Przeciągnij i przesuń z RecyclerView
źródło
Dodaję tę odpowiedź w celu szukania informacji w Google.
Niedawno pojawił się odcinek DevBytes ( ListView Cell Dragging and Rebranging ), który wyjaśnia, jak to zrobić
Możesz go znaleźć tutaj, również przykładowy kod jest dostępny tutaj .
To, co zasadniczo robi ten kod, polega na tym, że tworzy
dynamic listview
rozszerzenie,listview
które obsługuje przeciąganie i zamianę komórek. Abyś mógł użyćDynamicListView
zamiast swojego podstawowegoListView
i to wszystko, zaimplementowałeś ListView za pomocą przeciągania i upuszczania.źródło
Biblioteka DragListView robi to naprawdę schludnie z bardzo dobrą obsługą niestandardowych animacji, takich jak animacje wysokości. Jest również nadal utrzymywany i regularnie aktualizowany.
Oto jak go używasz:
1: Najpierw dodaj bibliotekę do gradle
dependencies { compile 'com.github.woxthebox:draglistview:1.2.1' }
2: Dodaj listę z xml
<com.woxthebox.draglistview.DragListView android:id="@+id/draglistview" android:layout_width="match_parent" android:layout_height="match_parent"/>
3: Ustaw odbiornik przeciągania
mDragListView.setDragListListener(new DragListView.DragListListener() { @Override public void onItemDragStarted(int position) { } @Override public void onItemDragEnded(int fromPosition, int toPosition) { } });
4: Utwórz kartę przesłoniętą z 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: Zaimplementuj element widoku, który rozszerza się z 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; } }
Aby uzyskać bardziej szczegółowe informacje, przejdź do https://github.com/woxblom/DragListView
źródło
Zauważyłem, że DragSortListView działa dobrze, chociaż rozpoczęcie pracy mogło być łatwiejsze. Oto krótki samouczek dotyczący używania go w Android Studio z listą w pamięci:
Dodaj to do
build.gradle
zależności dla swojej aplikacji:compile 'asia.ivity.android:drag-sort-listview:1.0' // Corresponds to release 0.6.1
Utwórz zasób dla identyfikatora uchwytu przeciągania, tworząc lub dodając do
values/ids.xml
:<resources> ... possibly other resources ... <item type="id" name="drag_handle" /> </resources>
Utwórz układ elementu listy, który zawiera twój ulubiony obraz uchwytu przeciągania i przypisz jego identyfikator do identyfikatora utworzonego w kroku 2 (np
drag_handle
.).Utwórz układ DragSortListView, coś takiego:
<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"/>
Ustaw
ArrayAdapter
pochodną zgetView
nadpisaniem, które renderuje widok elementu listy.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);
Ustaw odbiornik upuszczania, który przestawia elementy w miarę ich upuszczania.
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(); } });
źródło
Niedawno natknąłem się na ten wspaniały Gist, który daje działającą implementację typu przeciągania
ListView
, bez konieczności stosowania zewnętrznych zależności.Zasadniczo polega na utworzeniu własnego adaptera rozszerzającego się
ArrayAdapter
jako klasa wewnętrzna do działania zawierającegoListView
. Na tym adapterze ustawia się następnieonTouchListener
na elementy listy, które będą sygnalizować początek przeciągania.W tym streszczeniu ustawiają słuchacza na określoną część układu elementu listy („uchwyt” elementu), więc nie można przypadkowo przesunąć go przez naciśnięcie jakiejkolwiek jego części. Osobiście wolałem
onLongClickListener
zamiast tego, ale decyzja należy do ciebie. Oto fragment tej części: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; } }
Obejmuje to również dodanie
onTouchListener
doListView
, które sprawdza, czy element jest przeciągany, obsługuje zamianę i unieważnianie oraz zatrzymuje stan przeciągania. Fragment tej części: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; } });
Wreszcie, oto jak wyglądają metody
stopDrag
istartDrag
, które obsługują włączanie i wyłączanie procesu przeciągania:public void startDrag(String string) { mPosition = -1; mSortable = true; mDragString = string; mAdapter.notifyDataSetChanged(); } public void stopDrag() { mPosition = -1; mSortable = false; mDragString = null; mAdapter.notifyDataSetChanged(); }
źródło