¿Es posible usar elementos de lista expandibles con el nuevo RecyclerView? ¿Te gusta ExpandableListView?
¿Es posible usar elementos de lista expandibles con el nuevo RecyclerView? ¿Te gusta ExpandableListView?
Respuestas:
Esto es fácil de hacer con los LayoutManagers de stock, todo depende de cómo gestione su adaptador.
Cuando desee expandir una sección, simplemente agregue nuevos elementos a su adaptador después del encabezado. Recuerde llamar a notifyItemRangeInserted cuando haga esto. Para contraer una sección, simplemente elimine los elementos relevantes y llame a notifyItemRangeRemoved (). Para cualquier cambio de datos que se notifique adecuadamente, la vista del reciclador animará las vistas. Al agregar elementos, se crea un área para rellenar con los nuevos elementos, y los nuevos elementos van apareciendo. La eliminación es lo contrario. Todo lo que necesita hacer además de las cosas del adaptador es diseñar sus vistas para transmitir la estructura lógica al usuario.
Actualización: Ryan Brooks ahora ha escrito un artículo sobre cómo hacer esto.
Obtenga la implementación del código de muestra desde aquí
Establecer ValueAnimator dentro de onClick de ViewHolder
@Override
public void onClick(final View view) {
if (mOriginalHeight == 0) {
mOriginalHeight = view.getHeight();
}
ValueAnimator valueAnimator;
if (!mIsViewExpanded) {
mIsViewExpanded = true;
valueAnimator = ValueAnimator.ofInt(mOriginalHeight, mOriginalHeight + (int) (mOriginalHeight * 1.5));
} else {
mIsViewExpanded = false;
valueAnimator = ValueAnimator.ofInt(mOriginalHeight + (int) (mOriginalHeight * 1.5), mOriginalHeight);
}
valueAnimator.setDuration(300);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
view.getLayoutParams().height = value.intValue();
view.requestLayout();
}
});
valueAnimator.start();
}
Aquí está el código final
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView mFriendName;
private int mOriginalHeight = 0;
private boolean mIsViewExpanded = false;
public ViewHolder(RelativeLayout v) {
super(v);
mFriendName = (TextView) v.findViewById(R.id.friendName);
v.setOnClickListener(this);
}
@Override
public void onClick(final View view) {
if (mOriginalHeight == 0) {
mOriginalHeight = view.getHeight();
}
ValueAnimator valueAnimator;
if (!mIsViewExpanded) {
mIsViewExpanded = true;
valueAnimator = ValueAnimator.ofInt(mOriginalHeight, mOriginalHeight + (int) (mOriginalHeight * 1.5));
} else {
mIsViewExpanded = false;
valueAnimator = ValueAnimator.ofInt(mOriginalHeight + (int) (mOriginalHeight * 1.5), mOriginalHeight);
}
valueAnimator.setDuration(300);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
view.getLayoutParams().height = value.intValue();
view.requestLayout();
}
});
valueAnimator.start();
}
}
ExpandableListView
", porque el contenido expandido en ese caso es una lista en sí misma con elementos que provienen del adaptador. Esta es una solución degenerada con solo 1 elemento permitido como niños dentro del grupo.
https://github.com/gabrielemariotti/cardslib
Esta biblioteca tiene una implementación de una lista expandible con una vista de reciclaje (consulte la aplicación de demostración en "CardViewNative" -> "Lista, cuadrícula y RecyclerView" -> "Tarjetas expandibles"). También tiene muchas otras combinaciones interesantes de cartas / listas.
Alguien se quejó de que la solución mencionada anteriormente no se puede utilizar con una vista de lista como contenido expandible. Pero hay una solución simple: cree una vista de lista y complete esta vista de lista manualmente con sus filas .
Solución para los perezosos: hay una solución simple si no quieres cambiar mucho tu código. Simplemente use su adaptador manualmente para crear vistas y agréguelas al archivo LinearLayout
.
Este es el ejemplo:
if (mIsExpanded)
{
// llExpandable... is the expandable nested LinearLayout
llExpandable.removeAllViews();
final ArrayAdapter<?> adapter = ... // create your adapter as if you would use it for a ListView
for (int i = 0; i < adapter.getCount(); i++)
{
View item = adapter.getView(i, null, null);
// if you want the item to be selectable as if it would be in a default ListView, then you can add following code as well:
item.setBackgroundResource(Functions.getThemeReference(context, android.R.attr.selectableItemBackground));
item.setTag(i);
item.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// item would be retrieved with:
// adapter.getItem((Integer)v.getTag())
}
});
llExpandable.addView(item);
}
ExpandUtils.expand(llExpandable, null, 500);
}
else
{
ExpandUtils.collapse(llExpandable, null, 500);
}
funciones de ayuda: getThemeReference
public static int getThemeReference(Context context, int attribute)
{
TypedValue typeValue = new TypedValue();
context.getTheme().resolveAttribute(attribute, typeValue, false);
if (typeValue.type == TypedValue.TYPE_REFERENCE)
{
int ref = typeValue.data;
return ref;
}
else
{
return -1;
}
}
clase auxiliar: ExpandUtils
Kavin Varnan ya publicó cómo animar un diseño ... Pero si quieres usar mi clase, no dudes en hacerlo, publiqué una esencia: https://gist.github.com/MichaelFlisar/738dfa03a1579cc7338a
recyclerview
y puede expandir / ocultar esta anidada y usar todas las optimizaciones delrecyclerview
Puede usar ExpandableLayout como un CheckBox de animación de expansión / contracción suave, por lo que puede usarlo como CheckBox en ListView y RecyclerView.
Este es el código de muestra de lo que @TonicArtos menciona para agregar y eliminar elementos y animarlo mientras lo hace, esto se toma de la muestra de RecyclerView Animations y GitHub
1) Agregue Listener dentro de su onCreateViewHolder () para registrarse en onClick
2) Cree su OnClickListener personalizado dentro de su adaptador
private View.OnClickListener mItemListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
TextView tv = (TextView) v.findViewById(R.id.tvItems);
String selected = tv.getText().toString();
boolean checked = itemsList.get(recyclerView.getChildAdapterPosition(v)).isChecked();
switch (selected){
case "Item1":
if(checked){
deleteItem(v);
itemsList.get(recyclerView.getChildAdapterPosition(v)).setChecked(false);
}else {
addItem(v);
itemsList.get(recyclerView.getChildAdapterPosition(v)).setChecked(true);
}
break;
case "Item2":
if(checked){
deleteItem(v);
itemsList.get(recyclerView.getChildAdapterPosition(v)).setChecked(false);
}else {
addItem(v);
itemsList.get(recyclerView.getChildAdapterPosition(v)).setChecked(true);
}
break;
default:
//In my case I have checkList in subItems,
//checkItem(v);
break;
}
}
};
3) Agregue su addItem () y deleteItem ()
private void addItem(View view){
int position = recyclerView.getChildLayoutPosition(view);
if (position != RecyclerView.NO_POSITION){
navDrawItems.add(position+1,new mObject());
navDrawItems.add(position+2,new mObject());
notifyItemRangeInserted(position+1,2);
}
}
private void deleteItem(View view) {
int position = recyclerView.getChildLayoutPosition(view);
if (position != RecyclerView.NO_POSITION) {
navDrawItems.remove(position+2);
navDrawItems.remove(position+1);
notifyItemRangeRemoved(position+1,2);
}
}
4) Si su RecyclerViewAdapter no está en la misma actividad que Recycler View , pase la instancia de recyclerView al adaptador mientras crea
5) itemList es una ArrayList de tipo mObject que ayuda a mantener los estados del elemento (Abrir / Cerrar), nombre, tipo de elemento (subItems / mainItem) y establecer el tema en función de los valores
public class mObject{
private String label;
private int type;
private boolean checked;
}