
Na primeira parte, vimos o ItemTouchHelper e a implementação do ItemTouchHelper.Callback , que adiciona as funções básicas de arrastar e soltar e deslizar para dispensar no RecyclerView
. Neste artigo, continuaremos o que foi feito no anterior, adicionando suporte para organizar elementos na forma de uma grade, controladores de arrastar e soltar, seleção de um item da lista e animações de furto personalizadas.

Controladores de arrastar e soltar
Ao criar uma lista que suporta arrastar e soltar , eles geralmente implementam a capacidade de arrastar e soltar itens pelo toque. Isso contribui para a clareza e facilidade de uso da lista no "modo de edição" e também é recomendado pelas diretrizes do material. Adicionar controladores de arrastar e soltar ao nosso exemplo é incrivelmente fácil.

Primeiro, atualize o layout
elemento ( item_main.xml ).
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/item" android:layout_width="match_parent" android:layout_height="?listPreferredItemHeight" android:clickable="true" android:focusable="true" android:foreground="?selectableItemBackground"> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="16dp" android:textAppearance="?android:attr/textAppearanceMedium" /> <ImageView android:id="@+id/handle" android:layout_width="?listPreferredItemHeight" android:layout_height="match_parent" android:layout_gravity="center_vertical|right" android:scaleType="center" android:src="@drawable/ic_reorder_grey_500_24dp" /> </FrameLayout>
A imagem usada para o controlador de arrasto pode ser encontrada nos ícones do Material Design e adicionada ao projeto usando o conveniente plug-in gerador de ícones no Android Studio.
Conforme mencionado brevemente em um artigo anterior, você pode usar o ItemTouchHelper.startDrag(ViewHolder)
para iniciar programaticamente uma ItemTouchHelper.startDrag(ViewHolder)
de arrastar e soltar. Portanto, tudo o que precisamos fazer é atualizar o ViewHolder
adicionando um controlador de arrastar e configurar um manipulador de toque simples que chamará startDrag()
.
Vamos precisar de uma interface para transmitir eventos ao longo da cadeia:
public interface OnStartDragListener { void onStartDrag(RecyclerView.ViewHolder viewHolder); }
Em seguida, defina um ImageView
para o controlador de arrasto no ItemViewHolder
:
public final ImageView handleView; public ItemViewHolder(View itemView) { super(itemView);
e atualize o RecyclerListAdapter
:
private final OnStartDragListener mDragStartListener; public RecyclerListAdapter(OnStartDragListener dragStartListener) { mDragStartListener = dragStartListener;
RecyclerListAdapter
agora deve ser algo assim.
Tudo o que OnStartDragListener
ser feito é adicionar o OnStartDragListener
ao fragmento:
public class RecyclerListFragment extends Fragment implements OnStartDragListener {
RecyclerListFragment
agora deve ficar assim . Agora, quando você inicia o aplicativo, pode começar a arrastar e soltar tocando no controlador.

Destacando um Item da Lista
Agora, no nosso exemplo, não há indicação visual do item que está sendo arrastado. Obviamente, isso não deve ser, mas é fácil de corrigir. Usando o ItemTouchHelper
você pode usar os efeitos de destaque de itens padrão. No Lollipop e nas versões posteriores do Android, a luz de fundo "se espalha" sobre o elemento no processo de interação com ele; nas versões anteriores, o elemento simplesmente muda de cor para escurecido.
Para implementar isso em nosso exemplo, basta adicionar um plano de fundo (propriedade de background
) ao FrameLayout
raiz FrameLayout
elemento FrameLayout
ou defina-o no construtor RecyclerListAdapter.ItemViewHolder . Será algo parecido com isto:

Parece legal, mas você pode querer controlar ainda mais. Uma maneira de fazer isso é permitir que o ViewHolder
manipule as alterações de estado de um elemento. Para isso, o ItemTouchHelper.Callback
fornece mais dois métodos:
onSelectedChanged(ViewHolder, int)
é chamado toda vez que o estado de um elemento muda para arrastar ( ACTION_STATE_DRAG ) ou deslizar ( ACTION_STATE_SWIPE ). Este é o local ideal para alterar o estado do componente de view
para ativo .clearView(RecyclerView, ViewHolder)
é chamado quando o componente de view
arrastar e soltar é concluído e também quando o furto é concluído ( ACTION_STATE_IDLE ). Aqui, o estado inicial do seu componente de view
é geralmente restaurado.
Agora, vamos juntar tudo.
Primeiro, crie uma interface que o ViewHolders
implementará:
public interface ItemTouchHelperViewHolder { void onItemSelected(); void onItemClear(); }
Em seguida, no SimpleItemTouchHelperCallback
implemente os métodos apropriados:
@Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
Agora, tudo o que resta é que o RecyclerListAdapter.ItemViewHolder
implemente ItemTouchHelperViewHolder
:
public class ItemViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {
Neste exemplo, simplesmente adicionamos um plano de fundo cinza enquanto o elemento está ativo e o removemos. Se o ItemTouchHelper
e o adaptador estiverem intimamente conectados, você poderá abandonar facilmente essa configuração e alternar o estado do componente de view
diretamente em ItemTouchHelper.Callback
.
Redes
Se agora você tentar usar o GridLayoutManager
, verá que ele não funciona corretamente. O motivo e a solução são simples: precisamos informar ao ItemTouchHelper
que queremos suportar o arrastamento de itens para a esquerda e para a direita. Anteriormente, em SimpleItemTouchHelperCallback
, já especificamos:
@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); }
A única alteração necessária para dar suporte às grades é adicionar os sinalizadores apropriados:
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
No entanto, deslizar para dispensar não é um comportamento muito natural para elementos de grade, portanto, swipeFlags
mais provável que os swipeFlags
:
@Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; int swipeFlags = 0; return makeMovementFlags(dragFlags, swipeFlags); }
Para ver um exemplo de GridLayoutManager
funcionamento, consulte RecyclerGridFragment . Aqui está o que parece na inicialização:

Animações de furto personalizadas
ItemTouchHelper.Callback
fornece uma maneira realmente conveniente de controlar totalmente a animação enquanto arrasta ou varre. Como o ItemTouchHelper
é um RecyclerView.ItemDecoration , podemos intervir no processo de renderização de um componente de view
maneira semelhante. Na próxima parte, examinaremos essa questão com mais detalhes, mas, por enquanto, vejamos um exemplo simples de substituição da animação de furto padrão para mostrar um desaparecimento linear.
@Override public void onChildDraw(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { float width = (float) viewHolder.itemView.getWidth(); float alpha = 1.0f - Math.abs(dX) / width; viewHolder.itemView.setAlpha(alpha); viewHolder.itemView.setTranslationX(dX); } else { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } }
Os dY
dX
e dY
são o deslocamento atual em relação ao componente de view
selecionado, em que:
- -1.0f é um furto completo da direita para a esquerda (de
ItemTouchHelper.END
para ItemTouchHelper.START
) - 1.0f é furto completo da esquerda para a direita (de
ItemTouchHelper.START
para ItemTouchHelper.END
)
É importante chamar super
para qualquer actionState
que você não esteja processando para acionar a animação padrão.
Na próxima parte, consideraremos um exemplo no qual controlaremos o desenho de um elemento no momento do arrastar e soltar.
Conclusão
De fato, configurar o ItemTouchHelper é bastante divertido. Para não aumentar o volume deste artigo, dividi-o em vários.
Código fonte
Veja o código completo desta série de artigos nos repositórios Android-ItemTouchHelper-Demo GitHub. Este artigo aborda confirmações de ef8f149 a d164fba .
← Arraste e deslize o dedo no RecyclerView. Parte 1: ItemTouchHelper