Как правильно динамически изменять цвета у элементов recyclerview

Необходима ваша помощь. Есть адаптер для RecyclerView. В него приходит объект категории с некоторым содержимым, в том числе с полем, отвечающие за важность (в нем лежит 0 или 1). В зависимости от числа, я хотел бы изменять цвет layout. Изначально реализация была в методе bind.

      void bind(Category category) {
            nameCategory.setText(category.nameCategory);
            sumSpending.setText(String.valueOf(category.amountSpending));
            if (category.importance == 1) {
                nameCategoryBack.setBackgroundResource(R.drawable.back_name_necessary_category);
                layoutCategoryBack.setBackgroundResource(R.color.colorSecondaryDark);
            }
            this.category = category;
        }

Также я пробовал другую реализацию в методе onBindViewHolder().

    @Override
    public void onBindViewHolder(@NonNull final viewHolder holder, int position) {
        holder.bind(sortedList.get(position), expenses);
        if (holder.category.importance == 1) {
            holder.nameCategoryBack.setBackgroundResource(R.drawable.back_name_necessary_category);
            holder.layoutCategoryBack.setBackgroundResource(R.color.colorSecondaryDark);
        }
    }

Все идет хорошо, но после того как количество созданных элементов превысило число, после которого происходит замена содержимого элементов в RecyclerView, начинается некорректное отображение цвета layout, но содержимое остается верным. Как я могу правильно реализовать замену цветов фона layout?


Ответы (1 шт):

Автор решения: Sergei Buvaka

Как вы думаете, почему RecyclerView имеет такое название?

Вся его крутость заключается в переиспользовании элементов. RecyclerView реализует паттерн ViewHolder, суть которого заключается в том, что одновременно в памяти хранятся только те элементы которые помещаются на экране и несколько соседних.

введите сюда описание изображения

Вместо того чтоб постоянно вызывать метод findViewById() которой выполняется не очень быстро RecyclerView переиспользует те View которые больше не видны пользователю. И у нас появляется такое понятие как DirtyView - это View на которые уже не используются но на них хранится заданные параметры какого-то элемента.

И тут появляется прикол: если вы пишите в методе onBindViewHolder() какой-то if то в момент когда эта вьюшка переиспользуется она приходит в этот if и если if не true то она просто игнорирует биндинг этого поля. Таким образом там остается старое значение.

Отсюда следует правило: "Если в методе onBindViewHolder есть if то ВСЕГДА должен быть else" в противном случае у вас будут неверные параметры от старых биндингов.

→ Ссылка