android - studio - recyclerview
Crear ViewHolders para ListViews con diferentes diseƱos de elementos (2)
Tengo un ListView con diferentes diseños para diferentes elementos. Algunos artículos son separadores. Algunos elementos son diferentes porque contienen diferentes tipos de datos, etc.
Quiero implementar ViewHolders para acelerar el proceso getView, pero no estoy muy seguro de cómo hacerlo. Diferentes diseños tienen diferentes datos (lo que hace que nombrar sea difícil) y diferentes números de Vistas que quiero usar.
¿Cómo debo hacer esto?
La mejor idea que se me ocurre es crear un ViewHolder genérico con X elementos donde X es el número de Vistas en un diseño de elemento con el mayor número de ellas. Para las otras vistas con un número pequeño de Vistas, solo usaré una subsección de esas variables en el ViewHolder. Entonces, digo que tengo 2 diseños que uso para 2 artículos diferentes. Uno tiene 3 TextViews y el otro 1. He creado un ViewHolder con 3 variables TextView y solo uso 1 de ellos para el otro elemento. Mi problema es que esto puede ser realmente feo y se siente realmente hacky; especialmente cuando el diseño de un elemento puede tener muchas Vistas de muchos tipos diferentes.
Aquí hay un getView muy básico:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
MyHolder holder;
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.layout_mylistlist_item, parent, false);
holder = new MyHolder();
holder.text = (TextView) v.findViewById(R.id.mylist_itemname);
v.setTag(holder);
}
else {
holder = (MyHolder)v.getTag();
}
MyListItem myItem = m_items.get(position);
// set up the list item
if (myItem != null) {
// set item text
if (holder.text != null) {
holder.text.setText(myItem.getItemName());
}
}
// return the created view
return v;
}
Supongamos que tengo diferentes tipos de diseños de filas, podría tener un ViewHolder para cada tipo de fila. ¿Pero qué tipo declararía "titular" para estar en la parte superior? O declararía un titular para cada tipo y luego usaría el que corresponde al tipo de fila en la que estoy.
ListView tiene un sistema integrado de gestión de tipos. En su adaptador, tiene varios tipos de elementos, cada uno con su propia vista y diseño. Al anular getItemViewType para devolver el tipo de datos de una posición determinada, ListView se transfiere para pasar la conversión correcta para ese tipo de datos. Luego, en su método getView simplemente verifique el tipo de datos y use una declaración de cambio para manejar cada tipo de manera diferente.
Cada tipo de diseño debe tener su propio visor para nombrar la claridad y la facilidad de mantenimiento. Denomine a ViewHolders algo relacionado con cada tipo de datos para mantener todo en orden.
Intentar superponer todo en un solo ViewHolder no vale la pena.
Ejemplo de edición
@Override
public View getView(int position, View convertView, ViewGroup parent) {
int viewType = this.getItemViewType(position);
switch(viewType)
{
case TYPE1:
Type1Holder holder1;
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getContext().getSystemService (Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.layout_mylistlist_item_type_1, parent, false);
holder1 = new Type1Holder ();
holder1.text = (TextView) v.findViewById(R.id.mylist_itemname);
v.setTag(holder1);
}
else {
holder1 = (Type1Holder)v.getTag();
}
MyListItem myItem = m_items.get(position);
// set up the list item
if (myItem != null) {
// set item text
if (holder1.text != null) {
holder1.text.setText(myItem.getItemName());
}
}
// return the created view
return v;
case TYPE2:
Type2Holder holder2;
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.layout_mylistlist_item_type_2, parent, false);
holder2 = new Type2Holder ();
holder2.text = (TextView) v.findViewById(R.id.mylist_itemname);
holder2.icon = (ImageView) v.findViewById(R.id.mylist_itemicon);
v.setTag(holder1);
}
else {
holder2 = (Type2Holder)v.getTag();
}
MyListItem myItem = m_items.get(position);
// set up the list item
if (myItem != null) {
// set item text
if (holder2.text != null) {
holder2.text.setText(myItem.getItemName());
}
if(holder2.icon != null)
holder2.icon.setDrawable(R.drawable.icon1);
}
// return the created view
return v;
default:
//Throw exception, unknown data type
}
}
Otro ejemplo.
la clase pública CardArrayAdapter amplía ArrayAdapter {
public CardArrayAdapter(Context context) {
super(context, R.layout.adapter_card);
}
@Override
public View getView(int position, View view, ViewGroup parent) {
final Card card = getItem(position);
ViewHolder holder;
//if (view != null) {
//holder = (ViewHolder) view.getTag();
//} else {
Log.d("card.important?", card.name + " = " + Boolean.toString(card.important));
if(card.important) {
view = LayoutInflater.from(getContext()).inflate(R.layout.adapter_card_important, parent, false);
}else {
view = LayoutInflater.from(getContext()).inflate(R.layout.adapter_card, parent, false);
}
holder = new ViewHolder(view);
view.setTag(holder);
//}
// IMG
Picasso.with(getContext())
.load(card.logo)
.placeholder(R.drawable.ic_phonebook)
.error(R.drawable.ic_phonebook)
.fit()
.centerCrop()
.transform(new CircleTransform())
.into(holder.logo);
holder.name.setText(card.name);
if(card.important) {
holder.category.setVisibility(View.VISIBLE);
if (card.category.equals("airline")) {
card.category = "airlines";
}
int id = getContext().getResources().getIdentifier(card.category, "string", getContext().getPackageName());
holder.category.setText(getContext().getResources().getString(id));
}else {
holder.category.setVisibility(View.GONE);
}
holder.tagline.setText(card.tagline);
holder.favorite.setChecked(card.favorite);
holder.favorite.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
card.favorite = ((CheckBox) v).isChecked();
card.save();
}
});
return view;
}
static class ViewHolder {
@InjectView(R.id.logo) ImageView logo;
@InjectView(R.id.name) TextView name;
@InjectView(R.id.category) TextView category;
@InjectView(R.id.tagline) TextView tagline;
@InjectView(R.id.favorite) CheckBox favorite;
public ViewHolder(View view) {
ButterKnife.inject(this, view);
}
}
}