
Continuando con el artículo anterior , en este hablaré sobre ItemDecoration
y ItemAnimator
e intentaré explicar el principio de su trabajo en RecyclerView
usando un ejemplo de una aplicación simple que está disponible en Github .
1. Decoración del artículo
ItemDecoration
utiliza para decorar elementos de la lista en un RecyclerView
.
Con ItemDecoration
puede agregar divisores entre los componentes de la view
, alinearlos o dividirlos a intervalos iguales. Para agregar un separador simple entre los componentes de la view
, use la clase DividerItemDecoration
, que se puede encontrar en la biblioteca de soporte versión 25.1.0 y superior. El siguiente fragmento de código demuestra su implementación:
mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), mLayoutManager.getOrientation()); recyclerView.addItemDecoration(mDividerItemDecoration);
La mejor manera de crear su propio separador es extender la clase RecyclerView.ItemDecoration
. En la aplicación de muestra, utilicé el GridLayoutManager
y apliqué CharacterItemDecoration
al RecyclerView
:
recyclerView.addItemDecoration(new CharacterItemDecoration(50));
Aquí CharacterItemDecoration
establece el desplazamiento ( ing. Offset) en 50 píxeles en su constructor y anula getItemOffsets(...)
. Dentro del método getItemOffsets()
, cada campo outRects
determina el número de píxeles que se deben establecer para cada componente de view
, de forma similar a la sangría y la sangría. Como utilicé el GridLayoutManager
y quería establecer distancias iguales entre los elementos de la cuadrícula, configuré la sangría a la derecha en 25 píxeles (es decir, desplazamiento / 2) para cada elemento par y la sangría a la izquierda en 25 píxeles para cada elemento impar, mientras mantenía la sangría superior igual para todos los elementos

2. ItemAnimator
ItemAnimator
usa para animar elementos o view
componentes dentro de un RecyclerView
.

Hagamos que nuestra aplicación sea similar a Instagram extendiendo el DefaultItemAnimator
y anulando varios métodos.
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) { return true; }
El canReuseUpdatedViewHolder(...)
determina si se ViewHolder
el mismo ViewHolder
para la animación si los datos de este elemento cambian. Si devuelve false
, los dos ViewHolders
, antiguos y actualizados, se pasan al método animateChange(...)
.
public ItemHolderInfo recordPreLayoutInformation(@NonNull RecyclerView.State state, @NonNull RecyclerView.ViewHolder viewHolder, int changeFlags, @NonNull List<Object> payloads) { if (changeFlags == FLAG_CHANGED) { for (Object payload : payloads) { if (payload instanceof String) { return new CharacterItemHolderInfo((String) payload); } } } return super.recordPreLayoutInformation(state, viewHolder, changeFlags, payloads); } public static class CharacterItemHolderInfo extends ItemHolderInfo { public String updateAction; public CharacterItemHolderInfo(String updateAction) { this.updateAction = updateAction; } }
RecyclerView
llama al recordPreLayoutInformation(...)
para comenzar la representación del layout
. ItemAnimator
debe registrar la información necesaria sobre el componente de view
antes de que se sobrescriba, mueva o elimine. Los datos devueltos por este método se transferirán al método de animación correspondiente (en nuestro caso, esto es animateChange(...)
).
@Override public boolean animateChange(@NonNull RecyclerView.ViewHolder oldHolder, @NonNull RecyclerView.ViewHolder newHolder, @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) { if (preInfo instanceof CharacterItemHolderInfo) { CharacterItemHolderInfo recipesItemHolderInfo = (CharacterItemHolderInfo) preInfo; CharacterRVAdapter.CharacterViewHolder holder = (CharacterRVAdapter.CharacterViewHolder) newHolder; if (CharacterRVAdapter.ACTION_LIKE_IMAGE_DOUBLE_CLICKED.equals(recipesItemHolderInfo.updateAction)) { animatePhotoLike(holder); } } return false; } private void animatePhotoLike(final CharacterRVAdapter.CharacterViewHolder holder) { holder.likeIV.setVisibility(View.VISIBLE); holder.likeIV.setScaleY(0.0f); holder.likeIV.setScaleX(0.0f); AnimatorSet animatorSet = new AnimatorSet(); ObjectAnimator scaleLikeIcon = ObjectAnimator.ofPropertyValuesHolder (holder.likeIV, PropertyValuesHolder.ofFloat("scaleX", 0.0f, 2.0f), PropertyValuesHolder.ofFloat("scaleY", 0.0f, 2.0f), PropertyValuesHolder.ofFloat("alpha", 0.0f, 1.0f, 0.0f)); scaleLikeIcon.setInterpolator(DECELERATE_INTERPOLATOR); scaleLikeIcon.setDuration(1000); ObjectAnimator scaleLikeBackground = ObjectAnimator.ofPropertyValuesHolder (holder.characterCV, PropertyValuesHolder.ofFloat("scaleX", 1.0f, 0.95f, 1.0f), PropertyValuesHolder.ofFloat("scaleY", 1.0f, 0.95f, 1.0f)); scaleLikeBackground.setInterpolator(DECELERATE_INTERPOLATOR); scaleLikeBackground.setDuration(600); animatorSet.playTogether(scaleLikeIcon, scaleLikeBackground); animatorSet.start(); }
RecyclerView
llama al animateChange(...)
cuando el elemento adaptador está presente tanto antes como después de renderizar después de llamar al notifyItemChanged(int)
. Este método también se puede usar al llamar a notifyDataSetChanged()
, si el adaptador usa identificadores estables. Esto es necesario para que RecyclerView
pueda reutilizar los componentes de view
en los mismos ViewHolders
. Tenga en cuenta que este método toma como argumentos: (ViewHolder oldHolder, ViewHolder newHolder, ItemHolderInfo preInfo, ItemHolderInfo postInfo) . Como estamos reutilizando ViewHolder
, tanto oldHolder como newHolder son iguales.
Cada vez que el usuario hace doble clic en cualquier elemento, se llama al siguiente método:
notifyItemChanged(position, ACTION_LIKE_IMAGE_DOUBLE_CLICKED);
Esto inicia toda la cadena de llamadas: canReuseUpdatedViewHolder(...)
, recordPreLayoutInformation(...)
y, en última instancia, animateChange(...)
en ItemAnimator
, que, a su vez, anima el elemento de la lista y el ícono del corazón en este elemento ( ejemplo en el GIF anterior).
Esta es la segunda parte de una serie de artículos sobre RecyclerView
. Si te perdiste la primera parte, entonces léela aquí .
Algunos buenos artículos más sobre RecyclerView
:
← Consejos para uso profesional RecyclerView. Parte 1