
Existem muitos tutoriais, bibliotecas e implementações de arrastar e soltar e deslizar para dispensar no Android usando o RecyclerView. A maioria deles ainda usa o View.OnDragListener e a abordagem SwipeToDismiss , obsoleta , desenvolvida por Roman Nurik. Embora métodos novos e mais eficazes já estejam disponíveis. Muito poucos usam as APIs mais recentes, geralmente usando GestureDetectors
e onInterceptTouchEvent
ou outras implementações mais complexas. Na verdade, existe uma maneira muito simples de adicionar essas funções ao RecyclerView
. Isso requer apenas uma classe, que também faz parte da Biblioteca de Suporte do Android.
ItemTouchHelper
O ItemTouchHelper é um utilitário poderoso que cuida de tudo que você precisa para adicionar funções de arrastar e soltar e deslizar para dispensar no RecyclerView
. Esse utilitário é uma subclasse de RecyclerView.ItemDecoration , facilitando a adição a quase todos os LayoutManager
e adaptadores existentes. Ele também funciona com animação de elementos e fornece a capacidade de arrastar e soltar elementos de um tipo para outro lugar na lista e muito mais. Neste artigo, demonstrarei uma implementação simples do ItemTouchHelper
. Posteriormente, como parte desta série de artigos, expandiremos o escopo e consideraremos outras opções.
Nota Deseja ver o resultado imediatamente? Confira o Github: Android-ItemTouchHelper-Demo . O primeiro commit está relacionado a este artigo. O arquivo .apk
demonstração pode ser baixado aqui .

Personalização
Primeiro, precisamos configurar o RecyclerView
. Se você ainda não o fez, inclua a dependência do RecyclerView
em seu arquivo build.gradle
.
compile 'com.android.support:recyclerview-v7:22.2.0'
ItemTouchHelper
funcionará com praticamente qualquer RecyclerView.Adapter
e LayoutManager
, mas este artigo é baseado em exemplos usando esses arquivos .
Usando ItemTouchHelper e ItemTouchHelper.Callback
Para usar o ItemTouchHelper
, você precisa criar um ItemTouchHelper.Callback . Esta é uma interface que permite rastrear as ações de movimento ( eng. Mover) e deslizar ( eng. Deslizar). Além disso, aqui você pode controlar o estado do componente de view
selecionado e substituir a animação padrão. Há uma classe auxiliar que você pode usar se desejar usar a implementação básica, SimpleCallback . Mas, para entender como isso funciona na prática, faremos tudo sozinhos.
As principais funções da interface que devemos redefinir para incluir a funcionalidade básica de arrastar e soltar e deslizar para dispensar :
getMovementFlags(RecyclerView, ViewHolder) onMove(RecyclerView, ViewHolder, ViewHolder) onSwiped(ViewHolder, int)
Também usaremos vários métodos auxiliares:
isLongPressDragEnabled() isItemViewSwipeEnabled()
Vamos considerá-los um por um.
@Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(dragFlags, swipeFlags); }
ItemTouchHelper
facilita a determinação da direção de um evento. Você precisa substituir o método getMovementFlags()
para indicar quais instruções para arrastar e soltar serão suportadas. Para criar sinalizadores de retorno, use o método auxiliar ItemTouchHelper.makeMovementFlags(int, int)
. Neste exemplo, permitimos arrastar e soltar nas duas direções.
@Override public boolean isLongPressDragEnabled() { return true; }
ItemTouchHelper
pode ser usado apenas para arrastar e soltar sem a funcionalidade de furto (ou vice-versa), portanto, você deve especificar exatamente quais recursos devem ser suportados. O método isLongPressDragEnabled()
deve retornar true
para suportar arrastar e soltar após um longo clique no elemento RecyclerView
. Como alternativa, você pode chamar o ItemTouchHelper.startDrag(RecyclerView.ViewHolder)
para começar a arrastar manualmente. Consideraremos essa opção mais tarde.
@Override public boolean isItemViewSwipeEnabled() { return true; }
Para ativar o chicote após tocar em qualquer lugar do componente de view
, basta retornar true
partir do método isItemViewSwipeEnabled()
. Como alternativa, você pode chamar o ItemTouchHelper.startSwipe(RecyclerView.ViewHolder)
para iniciar o furto manualmente.
Os dois métodos a seguir, onMove()
e onSwiped()
, são necessários para notificá-lo sobre atualizações de dados. Portanto, primeiro criaremos uma interface que permitirá que esses eventos sejam transmitidos ao longo da cadeia de chamadas.
ItemTouchHelperAdapter.java
public interface ItemTouchHelperAdapter { void onItemMove(int fromPosition, int toPosition); void onItemDismiss(int position); }
A maneira mais fácil de fazer isso é fazer com que o RecyclerListAdapter implemente o ouvinte.
public class RecyclerListAdapter extends RecyclerView.Adapter<ItemViewHolder> implements ItemTouchHelperAdapter {
É muito importante chamar os notifyItemRemoved()
e notifyItemMoved()
para que o adaptador veja as alterações. Deve-se notar também que alteramos a posição do elemento toda vez que o componente view
é alterado para um novo índice, e não no final do movimento (o evento “drop”) .
Agora podemos voltar a criar SimpleItemTouchHelperCallback
, pois ainda precisamos substituir os onMove()
e onSwiped()
. Primeiro adicione o construtor e o campo para o adaptador:
private final ItemTouchHelperAdapter mAdapter; public SimpleItemTouchHelperCallback( ItemTouchHelperAdapter adapter) { mAdapter = adapter; }
Redefina os eventos restantes e relate isso ao adaptador:
@Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); return true; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { mAdapter.onItemDismiss(viewHolder.getAdapterPosition()); }
Como resultado, a classe Callback
deve se parecer com isso:
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback { private final ItemTouchHelperAdapter mAdapter; public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) { mAdapter = adapter; } @Override public boolean isLongPressDragEnabled() { return true; } @Override public boolean isItemViewSwipeEnabled() { return true; } @Override public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(dragFlags, swipeFlags); } @Override public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) { mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); return true; } @Override public void onSwiped(ViewHolder viewHolder, int direction) { mAdapter.onItemDismiss(viewHolder.getAdapterPosition()); } }
Quando o retorno de chamada está pronto, podemos criar um ItemTouchHelper
e chamar o attachToRecyclerView(RecyclerView)
(por exemplo, em MainFragment.java ):
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter); ItemTouchHelper touchHelper = new ItemTouchHelper(callback); touchHelper.attachToRecyclerView(recyclerView);
Depois de iniciar, você deve obter algo como o seguinte:

Conclusão
Esta é a implementação mais simplificada do ItemTouchHelper
. No entanto, você pode perceber que não precisa usar uma biblioteca de terceiros para implementar as ações padrão de arrastar e soltar e deslizar para dispensar no RecyclerView
. Na próxima parte, prestaremos mais atenção à aparência dos elementos no momento do arrastar e soltar.
Código fonte
Criei um projeto no GitHub para demonstrar o que é abordado nesta série de artigos: Android-ItemTouchHelper-Demo . O primeiro commit está relacionado principalmente a essa parte e um pouco à segunda .
→ Arraste e deslize o dedo no RecyclerView. Parte 2: arraste e solte controladores, grades e animações personalizadas