Deslize para dispensar para RecyclerView [fechado]

116

Eu costumava usar a biblioteca SwipeToDismiss , mas agora estou tentando migrar para o RecyclerView e as coisas não são tão óbvias, você conhece algum substituto para esta biblioteca? Alguma ideia de como implementá-lo do zero?

Viktor Yakunin
fonte
1
Eu criei uma pequena biblioteca que usa ItemTouchHelper para tornar a criação de gestos para recyclerview mais fácil, você pode encontrá-la aqui github.com/olmur/rvtools
Olexii Muraviov

Respostas:

337

A partir da v22.2.0, a equipe de suporte do Android incluiu uma ItemTouchHelperclasse que torna muito simples deslizar para dispensar e arrastar e soltar. Pode não ser tão completo quanto algumas das bibliotecas, mas vem diretamente da equipe do Android.

  • Atualize seu build.gradle para importar v22.2. + Da biblioteca RecyclerView

    compile 'com.android.support:recyclerview-v7:22.2.+'
  • Instancie um ItemTouchHelper com um SimpleCallback apropriado

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

    ** Observe que o SimpleCallback segue as direções que você deseja ativar para arrastar e soltar e as direções para as quais deseja ativar o deslize.

  • Anexe ao seu RecyclerView

    itemTouchHelper.attachToRecyclerView(recyclerView);
jmcdale
fonte
7
Como obter o índice do item roubado?
MaTTo
37
@Orochi Chamando getAdapterPosition () no viewHolder.
SqueezyMo
1
Eles claramente não pensaram muito no design desse componente. Ele só funciona com um RecyclerView. Deslizar para dispensar existe para itens como lanchonetes. Um componente mais genérico que pudesse ser usado com qualquer vista teria sido mais bem-vindo.
AndroidDev
4
E se eu quiser controlar o caso em que o usuário desliza parcialmente, mas arrasta a visualização de volta à posição? Aparentemente, isso não é possível (?) EDIT: ok, é possível, mas há uma pequena margem na qual você pode ficar antes que a visualização seja deslocada no lançamento. Alguma sugestão?
Matteo
2
@Matteo: Implementar ItemTouchHelper.Callback e substituir 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

Aqui no Código, se o usuário deslizar para a esquerda, AlertDialog é exibido e se o usuário selecionar REMOVER, o item é excluído do banco de dados e a visualização de reciclagem é atualizada e se o usuário selecionar CANCELAR, a visualização de reciclagem é como está.

Khyati Fatania
fonte
funcionando bem .. boa resposta.
Sagar Chavada de
Impressionante! Tão fácil de implementar
dianakarenms
1
Você realmente não precisa da verificação de direção, if (direction == ItemTouchHelper.LEFT) // if swipe leftpois o ItemTouchHelper.SimpleCallbacké limitado apenas a essa direção de deslize. Se você quiser deslizar para a esquerda e para a direita ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT), precisará verificar a direção.
Jacko,
1
Descobri que clicar fora do AlertDialog cancelou a caixa de diálogo, mas não colocou o item que deslizei de volta. Você pode capturar isso adicionando um OnCancelListener ao 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 funciona bem. Achei que adapter.notifyItemChanged(position);trouxe o item roubado de volta, em vez de notifyItemRemoved- o que é mais lógico, imho.
winwaed
14

talvez você possa experimentar esta biblioteca:

https://github.com/daimajia/AndroidSwipeLayout

Atualização: acabei de encontrar outra boa biblioteca que você pode usar com o RecyclerView:

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

Pierpaolo Paolini
fonte
Fiz minha própria implementação semelhante a github.com/krossovochkin/Android-SwipeToDismiss-RecyclerView . O único requisito era mostrar o Toast com o botão "Desfazer", que não está coberto em sua biblioteca.
Viktor Yakunin
1
A biblioteca da Daimajia não suporta o recurso deslizar para dispensar.
akohout
@raveN acabei de atualizar minha resposta.
Pierpaolo Paolini
2

Esta biblioteca pode ser útil. Você pode implementar undoem OnDissmissusosupertoast

xcodebuild
fonte
Ei, vou tentar! É baseado na resposta de Pierpaolo?
Garoto
É apenas uma OnTouchListener inspiração para isso
xcodebuild
2

Eu escrevi a biblioteca SwipeToDeleteRV que oferece suporte ao recurso deslizar para excluir-desfazer nas visualizações do reciclador. É baseado em ItemTouchHelper e muito fácil de usar.

Espero que possa ser útil para alguém que enfrenta os mesmos problemas.

Como exemplo, você pode definir a visualização do reciclador em um layout XML normalmente, além de alguns atributos opcionais:

...
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"/>

Todos os atributos stdrv são opcionais. Se você não especificá-los, os padrões serão usados.

Em seguida, crie um adaptador que subclasse STDAdapter, certifique-se de chamar o construtor da superclasse. Algo assim:

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

}

Em seguida, certifique-se de fazer uma chamada para o setupSwipeToDeletemétodo para configurar o recurso deslizar para excluir.

mRecyclerView.setupSwipeToDelete(your_adapter_instance, swipe_directions);

swipe_directions é a direção em que você permite que os itens sejam passados.

Exemplo:

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

É isso aí! Para configurações mais avançadas (ou seja, definir mensagens de exclusão diferentes para itens diferentes, remover itens temporária e permanentemente, ...) consulte a página leia-me do projeto.

H.Nguyen
fonte