Drag & Drop in RecyclerView mit GridLayoutManager

Was ich erreichen möchte: Habe einen RecyclerView mit GridLayoutManager, der Drag'n'Drop unterstützt und das beim Ziehen die Elemente umgibt.

Nebennote: Erstmaliges Waschen mit Drag & Drop.

Es gibt viele Themen, wie man diese Funktion mit einem ListView erreichen kann, zum Beispiel: https://raw.githubusercontent.com/btownrippleman/FurthestProgress/master/FurthestProgress/src/com/anappforthat/android/languagelineup/DynamicListView.java

Allerdings sind die Beispiele in der Regel eine Menge Code mit, Erstellen von Bitmaps der gezogenen Ansicht und es fühlt sich an, wie es möglich sein sollte, das gleiche Ergebnis mit View.startDrag(...) und RecyclerView mit notifyItemAdded() , notifyItemMoved() und notifyItemRemoved() da sie notifyItemRemoved() anordnen.

Also habe ich gegen einige gespielt und kam mit:

 final CardAdapter adapter = new CardAdapter(list); adapter.setHasStableIds(true); adapter.setListener(new CardAdapter.OnLongClickListener() { @Override public void onLongClick(View view) { ClipData data = ClipData.newPlainText("",""); View.DragShadowBuilder builder = new View.DragShadowBuilder(view); final int pos = mRecyclerView.getChildAdapterPosition(view); final Goal item = list.remove(pos); mRecyclerView.setOnDragListener(new View.OnDragListener() { int prevPos = pos; @Override public boolean onDrag(View view, DragEvent dragEvent) { final int action = dragEvent.getAction(); switch(action) { case DragEvent.ACTION_DRAG_LOCATION: View onTopOf = mRecyclerView.findChildViewUnder(dragEvent.getX(), dragEvent.getY()); int i = mRecyclerView.getChildAdapterPosition(onTopOf); list.add(i, list.remove(prevPos)); adapter.notifyItemMoved(prevPos, i); prevPos = i; break; case DragEvent.ACTION_DROP: View underView = mRecyclerView.findChildViewUnder(dragEvent.getX(), dragEvent.getY()); int underPos = mRecyclerView.getChildAdapterPosition(underView); list.add(underPos, item); adapter.notifyItemInserted(underPos); adapter.notifyDataSetChanged(); break; } return true; } }); view.startDrag(data, builder, view, 0); } }); mRecyclerView.setAdapter(adapter); 

Dieses Stück Code Art der Arbeit, ich bekomme das Swapping, aber sehr instabil / zittrig und manchmal, wenn es das ganze Raster erfrischt, wird wieder in die ursprüngliche Bestellung oder auf etwas zufälliges umgeordnet. Wie auch immer der Code oben ist nur mein erster schneller Versuch, was ich wirklich mehr daran interessiert bin zu wissen, ist, wenn es irgendeine Standard- / Best Practice-Möglichkeit gibt, den Drag & Drop mit ReyclerView zu machen oder wenn der richtige Weg, es zu lösen, immer noch dasselbe ist Seit Jahren für ListViews verwendet?

3 Solutions collect form web for “Drag & Drop in RecyclerView mit GridLayoutManager”

Es gibt tatsächlich einen besseren Weg, dies zu erreichen. Sie können einige der RecyclerView "Companion" Klassen verwenden:

ItemTouchHelper , das ist

Eine Utility-Klasse zum Hinzufügen von Swipe zu entlassen und Drag & Drop Unterstützung für RecyclerView.

Und seine ItemTouchHelper.Callback , die ist

Den Vertrag zwischen ItemTouchHelper und Ihrem Antrag

 // Create an `ItemTouchHelper` and attach it to the `RecyclerView` ItemTouchHelper ith = new ItemTouchHelper(_ithCallback); ith.attachToRecyclerView(rv); // Extend the Callback class ItemTouchHelper.Callback _ithCallback = new ItemTouchHelper.Callback() { //and in your imlpementaion of public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { // get the viewHolder's and target's positions in your adapter data, swap them Collections.swap(/*RecyclerView.Adapter's data collection*/, viewHolder.getAdapterPosition(), target.getAdapterPosition()); // and notify the adapter that its dataset has changed _adapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition()); return true; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { //TODO } //defines the enabled move directions in each state (idle, swiping, dragging). @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { return makeFlag(ItemTouchHelper.ACTION_STATE_DRAG, ItemTouchHelper.DOWN | ItemTouchHelper.UP | ItemTouchHelper.START | ItemTouchHelper.END); } }; 

Weitere Details finden Sie in der Dokumentation.

Dies ist meine Lösung mit Datenbank-Neuordnung:

  ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { final int fromPosition = viewHolder.getAdapterPosition(); final int toPosition = target.getAdapterPosition(); if (fromPosition < toPosition) { for (int i = fromPosition; i < toPosition; i++) { Collections.swap(mAdapter.getCapitolos(), i, i + 1); } } else { for (int i = fromPosition; i > toPosition; i--) { Collections.swap(mAdapter.getCapitolos(), i, i - 1); } } mAdapter.notifyItemMoved(fromPosition, toPosition); return true; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) { MyViewHolder svH = (MyViewHolder ) viewHolder; int index = mAdapter.getCapitolos().indexOf(svH.currentItem); mAdapter.getCapitolos().remove(svH.currentItem); mAdapter.notifyItemRemoved(index); if (emptyView != null) { if (mAdapter.getCapitolos().size() > 0) { emptyView.setVisibility(TextView.GONE); } else { emptyView.setVisibility(TextView.VISIBLE); } } } @Override public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { super.clearView(recyclerView, viewHolder); reorderData(); } }; ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback); itemTouchHelper.attachToRecyclerView(recList); 

Es gibt eine Unterstützung Funktionen tahat nutzen AsyncTask:

 private void reorderData() { AsyncTask<String, Void, Spanned> task = new AsyncTask<String, Void, Spanned>() { @Override protected Spanned doInBackground(String... strings) { dbService.deleteAllData(); for (int i = mAdapter.getCapitolos().size() - 1; i >= 0; i--) { Segnalibro s = mAdapter.getCapitolos().get(i); dbService.saveData(s.getIdCapitolo(), s.getVersetto()); } return null; } @Override protected void onPostExecute(Spanned spanned) { } }; task.execute(); } 

Ich fand Advancedrecyclerview sehr nützlich. Guck mal!!!

  • Wie behalte ich ViewPager-Status in einem RecyclerView?
  • Wie kann ich die erste Zeile in Recycler aussehen? Item Item für GridLayout?
  • Anzeigen von Firebase-Speicherbildern in einem RecyclerView
  • Android Studio 2.2.2 Fehler "Modus 0" auf Rendering Vorschau nach Update nicht lokalisieren
  • Gemeinsamer Elementübergang in RecyclerView
  • Warum benötigen CardView und RecyclerView minSdkVersion L?
  • Tragen Sie Offset auf GridLayout-Elemente an und bewahren Sie die gleiche Größe unter allen Elementen auf
  • NativeAdsExpress-Kräfte RecyclerView zu blättern, um das NativeAd vollständig sichtbar zu haben, wenn es zuerst geladen wird
  • Das Android ist ein Google Android Fan-Website, Alles ├╝ber Android Phones, Android Wear, Android Dev und Android Spiele Apps und so weiter.