Android: содержимое RecyclerView перепуталось после прокрутки
Я использую RecyclerView для отображения списка меток, и каждый знак значения отображается как CardView. Но некоторое содержимое карт теряется после прокрутки RecyclerView вниз и прокрутки назад, как показано на двух снимках экрана ниже. Содержимое в красном прямоугольнике теряется после прокрутки.
ПЕРЕД ОБРАБОТКОЙ;
![enter image description here]()
ПОСЛЕ ОБРАЩЕНИЯ,
![enter image description here]()
Мне интересно, является ли это ошибкой RecyclerView и не найдено никакого решения после Googling для него.
Все виды невидимы, за исключением названия, их видимость зависит от значения метки.
Кто-нибудь знает, почему это произойдет?
Ответы
Ответ 1
onBindHolder вызывается несколько раз, так как новостям ресайклера требуется просмотр, если только новый.
Поэтому каждый раз, когда вы устанавливаете видимость в дочерних представлениях, другие состояния представлений также являются изменениями.
Всякий раз, когда вы прокручиваете вверх и вниз, эти представления получают повторное рисование с неправильными параметрами видимости.
Решение:
У вас есть значение проверки метода setValue и установлено для просмотра. Если необходимо, он вызывает другой метод "showView". Вам нужно реализовать инструкцию else (которая равна 0 или null) и hideView там...
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);
}
Ответ 2
После битвы с этой же проблемой в течение примерно 24 часов я нашел решение, которое сработало для меня. Ключ использовал метод setIsRecyclable()
класса RecyclerView.ViewHolder
.
Вот раздел моего кода 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);
}
});
}
Ответ 3
onBindHolder вызывается несколько раз, так как Recycler View нуждается в представлении, если только новый. Таким образом, каждый раз, когда вы устанавливаете visilibity в дочерних представлениях, другие состояния представлений также изменяются.
Всякий раз, когда вы прокручиваете вверх и вниз, эти представления получают повторное рисование с неправильными параметрами видимости, поэтому всегда указывайте оба условия, вызывающие просмотр ресайклера, не знают предыдущего состояния/условий/значений наших виджетов.
Решение:
Если в блоке If вы устанавливаете видимость любого виджета android widget.setVisibility(View.Gone), тогда в блоке else вы должны установить его видимость напротив v widget.setVisibility(View.Visible), чтобы преодолеть вышеупомянутую проблему.
@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 opposite visibility i set.
viewHolder.tvPrice.setTextColor(Color.parseColor("#ff0000"));
viewHolder.tvPrice.setPaintFlags(0);// here paint flag is 0 and in else it 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);
}
}
});
}
Ответ 4
Это происходит из-за повторного использования представлений при прокрутке. Чтобы исправить это, вам понадобится reset любые виды, которые были сделаны видимыми для других ячеек (YUZME в вашем примере).
Внутри setValue (значение Object, TextView textView, строка TableRow, просмотр seperator) просто снова закроет все txtVize *.
Рециклирующее представление начинается с 3 просмотров:
[0] FIZ104
[1] MAT102
[2] REK361
Когда просмотр прокручивается в нижние виды, [0] и [1] возвращаются в исходное состояние. При прокрутке назад к верхнему виду [2] используется для отображения данных, содержащихся в FIZ104 и MAT102, и все изменения, сделанные для REK361, все еще существуют.
Ответ 5
Если вы столкнулись с проблемами с проблемой видимости для ex. если вы установили видимость представления на основе условия, но если вы прокрутите вниз, просмотры будут обновлены, а видимость представления внутри этого объекта просмотра ресайклера будет изменена и, следовательно, нарушит условие.
Здесь решение:
1. Сначала назначьте тег этому виду, видимость которого вы хотите сохранить.
holder.myImageView.setTag(myTeamLists.get(position));
MyDTOClass checkWetherToShow=(MyDTOClass)holder.myImageView.getTag();
2. Теперь примените свое условие и переключите видимость
if (checkWetherToShow.getHasToShowImage()){
holder.myImageView.setVisibility(View.VISIBLE);
}else{
holder.myImageView.setVisibility(View.GONE);
}
Ключ к ответу здесь не забывайте о части else.