Przesuń, aby zamknąć dla RecyclerView [zamknięte]

116

Kiedyś korzystałem z biblioteki SwipeToDismiss, ale teraz próbuję migrować do RecyclerView i sprawy nie są takie oczywiste, czy znasz jakieś zamienniki tej biblioteki? Jakieś pomysły jak zrealizować to od podstaw?

Viktor Yakunin
źródło
1
Zrobiłem małą bibliotekę, która używa ItemTouchHelper, aby ułatwić tworzenie gestów do recyclingu, możesz ją znaleźć tutaj github.com/olmur/rvtools
Olexii Muraviov

Odpowiedzi:

337

Począwszy od wersji 22.2.0, zespół pomocy technicznej Androida zawiera ItemTouchHelperklasę, która sprawia, że ​​przeciąganie w celu odrzucenia oraz przeciąganie i upuszczanie jest całkiem proste. Może nie być tak w pełni funkcjonalny, jak niektóre biblioteki, ale pochodzi bezpośrednio od zespołu Androida.

  • Zaktualizuj plik build.gradle, aby zaimportować wersję 22.2. + Biblioteki RecyclerView

    compile 'com.android.support:recyclerview-v7:22.2.+'
  • Utwórz wystąpienie ItemTouchHelper z odpowiednim SimpleCallback

    ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
        [...]
        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
            //Remove swiped item from list and notify the RecyclerView
        }
    };
    
    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
    

    ** Zwróć uwagę, że SimpleCallback przyjmuje kierunki, w których chcesz włączyć funkcję przeciągania i upuszczania, oraz kierunki, w których chcesz włączyć przesuwanie.

  • Dołącz do swojego RecyclerView

    itemTouchHelper.attachToRecyclerView(recyclerView);
jmcdale
źródło
7
Jak uzyskać indeks przesuniętego elementu?
MaTTo
37
@Orochi Wywołując metodę getAdapterPosition () w viewHolder.
SqueezyMo
1
Najwyraźniej nie poświęcili zbyt wiele uwagi projektowi tego elementu. Działa tylko z RecyclerView. W przypadku takich rzeczy, jak batony z przekąskami, istnieje opcja „przeciągnij, aby odrzucić”. Bardziej ogólny komponent, którego można by użyć w dowolnym widoku, byłby bardziej pożądany.
AndroidDev
4
A jeśli chcę zająć się przypadkiem, gdy użytkownik przesuwa palcem częściowo, a następnie przeciąga widok z powrotem na miejsce? Najwyraźniej nie jest to możliwe (?) EDYCJA: ok, to jest możliwe, ale jest bardzo mały margines, na którym można pozostać, zanim widok zostanie przesunięty po wydaniu. Jakieś sugestie?
Matteo
2
@Matteo: Zaimplementuj ItemTouchHelper.Callback i zastąp getSwipeThreshold ()
Sofi Software LLC
36
 ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
            return false;
        }

        @Override
        public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction) {
            final int position = viewHolder.getAdapterPosition(); //get position which is swipe

            if (direction == ItemTouchHelper.LEFT) {    //if swipe left

                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); //alert for confirm to delete
                builder.setMessage("Are you sure to delete?");    //set message

                builder.setPositiveButton("REMOVE", new DialogInterface.OnClickListener() { //when click on DELETE
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        adapter.notifyItemRemoved(position);    //item removed from recylcerview
                        sqldatabase.execSQL("delete from " + TABLE_NAME + " where _id='" + (position + 1) + "'"); //query for delete
                        list.remove(position);  //then remove item

                        return;
                    }
                }).setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {  //not removing items if cancel is done
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        adapter.notifyItemRemoved(position + 1);    //notifies the RecyclerView Adapter that data in adapter has been removed at a particular position.
                        adapter.notifyItemRangeChanged(position, adapter.getItemCount());   //notifies the RecyclerView Adapter that positions of element in adapter has been changed from position(removed element index to end of list), please update it.
                        return;
                    }
                }).show();  //show alert dialog
            }
        }
    };
    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleCallback);
    itemTouchHelper.attachToRecyclerView(recyclerView); //set swipe to recylcerview

Tutaj w kodzie, jeśli użytkownik przesunie palcem w lewo, zostanie wyświetlony komunikat AlertDialog, a jeśli użytkownik wybierze opcję USUŃ, element zostanie usunięty z bazy danych, a przegląd recyklingu zostanie odświeżony, a jeśli użytkownik wybierze opcję ANULUJ, widok programu recyklingowego jest taki, jaki jest.

Khyati Fatania
źródło
działa dobrze .. miła odpowiedź.
Sagar Chavada
Niesamowite! Tak łatwe do wdrożenia
dianakarenms
1
Naprawdę nie potrzebujesz sprawdzania kierunku, if (direction == ItemTouchHelper.LEFT) // if swipe leftponieważ ItemTouchHelper.SimpleCallbackjest on ograniczony tylko do tego kierunku przesunięcia. Jeśli chcesz przesunąć w lewo i w prawo, wtedy ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT)musisz sprawdzić kierunek.
Jacko
1
Zauważyłem, że kliknięcie poza AlertDialog anulowało okno dialogowe, ale nie umieściło elementu, który przesunąłem z powrotem. Możesz to uchwycić, dodając OnCancelListener do BuilderAlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);builder.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { // stuff to put the item back } });
Jacko
1
+1 Działa dobrze. Okazało się, że adapter.notifyItemChanged(position);przyniosłem przesunięty przedmiot z powrotem, a nie notifyItemRemoved- co jest bardziej logiczne imho.
Winwaed
14

może mógłbyś wypróbować tę bibliotekę:

https://github.com/daimajia/AndroidSwipeLayout

Aktualizacja: właśnie znalazłem kolejną dobrą bibliotekę, której możesz używać z RecyclerView:

https://github.com/hudomju/android-swipe-to-dismiss-undo

Pierpaolo Paolini
źródło
Zrobiłem własną implementację podobną do github.com/krossovochkin/Android-SwipeToDismiss-RecyclerView . Jedynym wymaganiem było pokazanie Toast z przyciskiem „Cofnij”, co nie jest uwzględnione w Twojej bibliotece.
Viktor Yakunin
1
Biblioteka firmy Daimajia nie obsługuje funkcji „przeciągnij, aby zamknąć”.
akohout
@raveN Właśnie zaktualizowałem moją odpowiedź.
Pierpaolo Paolini
2

Ta biblioteka może być pomocna.Możesz zaimplementować undow OnDissmissużyciusupertoast

xcodebuild
źródło
Hej, spróbuję! Czy jest to oparte na odpowiedzi Pierpaolo?
Chłopiec
To tylko OnTouchListener inspirować przez to
xcodebuild
2

Napisałem bibliotekę SwipeToDeleteRV, która obsługuje funkcję przeciągnij, aby usunąć i cofnąć w widokach recyklera. Opiera się na ItemTouchHelper i jest bardzo łatwy w użyciu.

Mam nadzieję, że może to być pomocne dla kogoś, kto ma te same problemy.

Na przykład możesz zdefiniować widok recyklera w układzie XML jako normalny, plus kilka opcjonalnych atrybutów:

...
xmlns:stdrv="http://schemas.android.com/apk/res-auto"
...
<io.huannguyen.swipetodeleterv.STDRecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
stdrv:border_color="@android:color/darker_gray" // specify things like border color, border width, etc.
stdrv:delete_view_background="#cccccc"
stdrv:delete_icon="@drawable/ic_archive"
stdrv:delete_icon_height="24dp"
stdrv:delete_icon_width="24dp"
stdrv:left_delete_icon_margin="32dp"
stdrv:delete_message="@string/delete_message"
stdrv:right_delete_icon_margin="32dp"
stdrv:delete_icon_color="#000000"
stdrv:has_border="true"/>

Wszystkie atrybuty stdrv są opcjonalne. Jeśli ich nie określisz, zostaną użyte domyślne.

Następnie utwórz adapter, który jest podklasą STDAdapter, upewnij się, że wywołujesz konstruktora superklasy. Coś takiego:

public class SampleAdapter extends STDAdapter<String> {
public SampleAdapter(List<String> versionList) {
    super(versionList);
}

}

Następnie upewnij się, że wywołałeś setupSwipeToDeletemetodę, aby ustawić funkcję przeciągnij, aby usunąć.

mRecyclerView.setupSwipeToDelete(your_adapter_instance, swipe_directions);

swipe_directions to kierunek, w którym możesz przesuwać elementy.

Przykład:

// Get your recycler view from the XML layout
mRecyclerView = (STDRecyclerView) findViewById(R.id.recycler_view);
LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
mRecyclerView.setLayoutManager(layoutManager);
mAdapter = new SampleAdapter(versions);
// allow swiping in both directions (left-to-right and right-to-left)
mRecyclerView.setupSwipeToDelete(mAdapter, ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT);

Otóż ​​to! Bardziej zaawansowane ustawienia (np. Ustawianie różnych komunikatów o usuwaniu różnych elementów, tymczasowe i trwałe usuwanie elementów, ...) można znaleźć na stronie Readme projektu.

H.Nguyen
źródło