studio - Android: el contenido de RecyclerView se desordenó después de desplazarse
refresh recyclerview android studio (5)
Estoy usando RecyclerView para mostrar una lista de marcas, y cada marca del valor se muestra como un CardView. Pero algunos contenidos de las tarjetas se pierden después de desplazar el RecyclerView hacia abajo y hacia atrás, como se muestra en las dos capturas de pantalla a continuación. El contenido en el rectángulo rojo se pierde después de desplazarse.
ANTES DEL DESPLAZAMIENTO;
DESPUÉS DEL DESPLAZAMIENTO;
Me pregunto si es un error de RecyclerView y no encontrar una solución después de buscarlo en Google.
Todas las vistas son invisibles, excepto el título, sus visibilidades dependen del valor de la marca.
¿Alguien sabe porqué podría pasar esto?
Después de luchar con este mismo problema durante aproximadamente 24 horas, encontré una solución que funcionó para mí. La clave estaba usando el método setIsRecyclable()
de la clase RecyclerView.ViewHolder
.
Aquí hay una sección de mi código onBindViewHolder()
.
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
final DataSource dataSource = dataSourceList.get(position);
holder.setIsRecyclable(false);
holder.name.setText(dataSource.getName());
holder.active.setChecked(dataSource.getActive());
String logoStr = dataSource.getLogo();
//Logo
/**
* Do all the logo insertion stunts here
*/
/**
* Register the changes to the Switch
*/
holder.active.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked){
dataSource.setActive(isChecked);
}
});
}
Esto se debe a que las vistas se reutilizan cuando se produce el desplazamiento. Para solucionar este problema, deberá restablecer las vistas que se han hecho visibles para otras celdas (YUZME en su ejemplo).
Dentro de setValue (valor del objeto, TextView textView, TableRow row, View seperator) simplemente hace que todos los txtVize * se oculten de nuevo.
La vista del reciclador comienza con 3 vistas:
[0] FIZ104
[1] MAT102
[2] REK361
Cuando la vista se desplaza a las vistas inferiores [0] y [1] se reciclan. Cuando se desplaza de nuevo a la vista superior, [2] se utiliza para mostrar los datos contenidos en FIZ104 y MAT102 y todos los cambios realizados para REK361 todavía están allí.
Si está enfrentando problemas con el problema de visibilidad por ej. si ha establecido la visibilidad de la vista según la condición, pero si se desplaza hacia abajo, las vistas se actualizan y la visibilidad de la vista dentro de ese elemento de la vista de reciclador se modifica y, por lo tanto, se viola la condición.
Aquí hay una solución:
1. Primero asigne una etiqueta a esa vista cuya visibilidad desea mantener.
holder.myImageView.setTag(myTeamLists.get(position));
MyDTOClass checkWetherToShow=(MyDTOClass)holder.myImageView.getTag();
2. Ahora aplica tu condición y cambia la visibilidad
if (checkWetherToShow.getHasToShowImage()){
holder.myImageView.setVisibility(View.VISIBLE);
}else{
holder.myImageView.setVisibility(View.GONE);
}
La clave para la respuesta aquí es no olvidar la otra parte .
onBindHolder llamó varias veces, ya que el reciclador necesita una vista, a menos que haya una nueva en el caso del tipo de vista cambiado. Por lo tanto, cada vez que configura la visibilidad en las vistas secundarias, también cambian los estados de otras vistas.
Cada vez que se desplaza hacia arriba y hacia abajo, estas vistas se vuelven a dibujar con opciones de visibilidad erróneas.
Solución:
Usted tiene un método setValue que verifica los valores y lo configura para ver. Si es necesario, llama a otro método "showView". Debe implementar la instrucción else (que es un valor 0 o nulo) y hideView allí ...
void setValue(Object value, TextView textView, TableRow row, View seperator) {
if (value != null) {
if (!isEmpty(value.toString())) {
textView.setText(String.valueOf(value));
showViews(row, seperator);
}
} else
hideViews(row, seperator);
}
private void showViews(TableRow row, View seperator) {
row.setVisibility(View.VISIBLE);
seperator.setVisibility(View.VISIBLE);
}
private void hideViews(TableRow row, View seperator) {
row.setVisibility(View.INVISIBLE); // if there is a empty space change it with View.GONE
seperator.setVisibility(View.INVISIBLE);
}
onBindHolder llama varias veces, ya que la vista Recycler necesita una vista a menos que sea una nueva. Por lo tanto, cada vez que configura la visibilidad en las vistas secundarias, también cambian los estados de otras vistas.
Cada vez que se desplaza hacia arriba y hacia abajo, estas vistas se vuelven a dibujar con opciones de visibilidad erróneas, por lo que siempre especifique las condiciones que causan que la vista del reciclador no conozca el estado / condiciones / valores anteriores de nuestros widgets.
Solución:
Si en el bloque If, configura la visibilidad de cualquier widget.setVisibility (View.Gone) de Android, el bloque else tiene que establecer su visibilidad opuesta a widget.setVisibility (View.Visible) para superar el problema anterior.
@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
viewHolder.tvName.setText(ModelCategoryProducts.name.get(i));
viewHolder.tvPrice.setText("Rs."+String.format("%.2f", Float.parseFloat(ModelCategoryProducts.price.get(i))));
if(ModelCategoryProducts.special_price.get(i).equals("null")) {
viewHolder.tvSpecialPrice.setVisibility(View.GONE); // here visibility is gone and in else it''s opposite visibility i set.
viewHolder.tvPrice.setTextColor(Color.parseColor("#ff0000"));
viewHolder.tvPrice.setPaintFlags(0);// here paint flag is 0 and in else it''s opposite flag that i want is set.
}else if(!ModelCategoryProducts.special_price.get(i).equals("null")){
viewHolder.tvPrice.setTextColor(Color.parseColor("#E0E0E0"));
viewHolder.tvSpecialPrice.setVisibility(View.VISIBLE);
viewHolder.tvSpecialPrice.setText("Rs." + String.format("%.2f", Float.parseFloat(ModelCategoryProducts.special_price.get(i))));
viewHolder.tvPrice.setPaintFlags(viewHolder.tvPrice.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
if (!ModelCategoryProducts.image_url.get(i).isEmpty()) {
Picasso.with(context)
.load(ModelCategoryProducts.image_url.get(i))
.into(viewHolder.ivProduct);
}
viewHolder.setClickListener(new ItemClickListener() {
@Override
public void onClick(View view, int position, boolean isLongClick) {
if (isLongClick) {
// Toast.makeText(context, "#" + position + " - " + ModelCategoryProducts.name.get(position) + " (Long click)", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "#" + position + " - " + ModelCategoryProducts.name.get(position), Toast.LENGTH_SHORT).show();
Intent i = new Intent(context, ProductDetail.class);
i.putExtra("position",position);
i.putExtra("flagHlvCheck", 5);
context.startActivity(i);
}
}
});
}