Simplemente no hay necesidad de usar bibliotecas de terceros. Un pequeño ajuste en el método demostrado en Google I / O 2016 y Heisenberg sobre este tema, es el truco.
Dado que se notifyDataSetChanged() vuelve a dibujar el completoRecyclerView , notifyDataItemChanged()es una mejor opción (no la mejor) porque tenemos la posición y el ViewHoldera nuestra disposición, y notifyDataItemChanged()solo se vuelve a dibujar lo particular ViewHolderen una posición determinada .
Pero el problema es que la desaparición prematura del ViewHolderclic y su aparición no se eliminan aunque notifyDataItemChanged()se utilicen.
El siguiente código no recurre notifyDataSetChanged()ni notifyDataItemChanged()se prueba en API 23 y funciona de maravilla cuando se usa en un RecyclerView donde cada ViewHolder tiene un CardViewelemento raíz:
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final boolean visibility = holder.details.getVisibility()==View.VISIBLE;
if (!visibility)
{
holder.itemView.setActivated(true);
holder.details.setVisibility(View.VISIBLE);
if (prev_expanded!=-1 && prev_expanded!=position)
{
recycler.findViewHolderForLayoutPosition(prev_expanded).itemView.setActivated(false);
recycler.findViewHolderForLayoutPosition(prev_expanded).itemView.findViewById(R.id.cpl_details).setVisibility(View.GONE);
}
prev_expanded = position;
}
else
{
holder.itemView.setActivated(false);
holder.details.setVisibility(View.GONE);
}
TransitionManager.beginDelayedTransition(recycler);
}
});
prev_positiones un entero global inicializado en -1.
detailses la vista completa que se muestra cuando se expande y se oculta cuando se contrae.
Como se dijo, el elemento raíz de ViewHolderes un CardViewcon foregroundy stateListAnimatoratributos definidos exactamente como lo dijo Heisenberg sobre este tema.
ACTUALIZACIÓN: La demostración anterior colapsará el elemento previamente expandido si uno de ellos está expandido. Para modificar este comportamiento y mantener el elemento expandido como está, incluso cuando se expande otro elemento, necesitará el siguiente código.
if (row.details.getVisibility()!=View.VISIBLE)
{
row.details.setVisibility(View.VISIBLE);
row.root.setActivated(true);
row.details.animate().alpha(1).setStartDelay(500);
}
else
{
row.root.setActivated(false);
row.details.setVisibility(View.GONE);
row.details.setAlpha(0);
}
TransitionManager.beginDelayedTransition(recycler);
ACTUALIZACIÓN: al expandir los últimos elementos de la lista, es posible que no se muestre completamente porque la parte expandida va debajo de la pantalla. Para obtener el elemento completo dentro de la pantalla, use el siguiente código.
LinearLayoutManager manager = (LinearLayoutManager) recycler.getLayoutManager();
int distance;
View first = recycler.getChildAt(0);
int height = first.getHeight();
int current = recycler.getChildAdapterPosition(first);
int p = Math.abs(position - current);
if (p > 5) distance = (p - (p - 5)) * height;
else distance = p * height;
manager.scrollToPositionWithOffset(position, distance);
IMPORTANTE: Para que las demostraciones anteriores funcionen, uno debe mantener en su código una instancia de RecyclerView y su LayoutManager (el último para flexibilidad)