Подтвердить что ты не робот

RecyclerView - получить все существующие виды/зрители

Я хочу обновить RecyclerView, пока он отображает данные, в моем случае я показываю изображения с метками или без них.

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

Можно ли каким-то образом получить все существующие Views? Мне нужны все, а не только видимые, я не хочу, чтобы более поздняя утилизация View не обновлялась...

4b9b3361

Ответ 1

В классе адаптера:

Boolean isVisible = false;

public CustomAdapter(boolean isVisible) {
    this.isVisible= isVisible;
}
    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
     ...

         if (isVisible){
           //setVisibility(View.VISIBLE)
         }else{
         //setVisibility(View.INVISIBLE
         }
    }

public void updateVisibility(boolean newValue){
 isVisible= newValue;
}

В Activity где вы хотите обновить значение, в котором создается экземпляр адаптера:

adapter.updateVisibility(false);
adapter.notifydataSetChanged();

Ответ 2

Сначала вам нужно получить все показанные индексы представлений, а затем вам нужно просмотреть каждый из них и использовать viewHolder каждого представления:

final int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();
final int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition();
for (int i = firstVisibleItemPosition; i <= lastVisibleItemPosition; ++i) {
    ViewHolder holder = (ViewHolder) mRecyclerView.findViewHolderForAdapterPosition(i);
    ...
    }

РЕДАКТИРОВАТЬ: кажется, он не всегда возвращает все ViewHolders, которые вы, возможно, захотите обработать. Это выглядит как более стабильное решение:

for (int childCount = recyclerView.getChildCount(), i = 0; i < childCount; ++i) {
   final ViewHolder holder = recyclerView.getChildViewHolder(recyclerView.getChildAt(i));
   ...
   }

Примечание: в некоторых случаях вам может потребоваться установить достаточно большое количество кэшируемых представлений, чтобы вы всегда возвращали одни и те же представления вместо новых. Для этого вы можете использовать что-то вроде этого:

fun RecyclerView.setMaxViewPoolSize(maxViewTypeId: Int, maxPoolSize: Int) {
    for (i in 0..maxViewTypeId)
        recycledViewPool.setMaxRecycledViews(i, maxPoolSize)
}

Пример использования:

recyclerView.setMaxViewPoolSize(PhoneCallRecordingListActivityViewModel.ListItem.MAX_TYPE_ITEM, Int.MAX_VALUE)

Ответ 3

  • Обновление всего размера списка адаптеров с помощью notifyDataSetChanged() не удобно.
  • Получить все текущие дочерние элементы RecyclerView (т.е. Все видимые элементы) недостаточно: есть привязанные держатели вида, которые не видны: после загрузки при запуске обычно 2 или 3 элемента привязаны к последней видимой позиции (в зависимости от вашего LayoutManager),

Я просто экспериментировал, просматривая логи, которые я помещал, что RV связывает больше предметов, которые не видны, на самом деле я не нашел способа восстановить их. Я закончил кешировать в Set или List те ViewHolders в onBindViewHolder() и разархивировать их в onViewRecycled():

private Set<AbstractViewHolder> mBoundViewHolders = new HashSet<>();
private int mVisibility = View.VISIBILE;

// So you can have access from the Activity/Fragment
public Set<AbstractViewHolder> getAllBoundViewHolders() {
    return Collections.unmodifiableSet(mBoundViewHolders);
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, List payloads) {
    // Binding code
    ...
    holder.view.setVisibility(mVisibility);

    // Caching VH
    mBoundViewHolders.add((AbstractViewHolder) holder);
}

@Override
public void onViewRecycled(RecyclerView.ViewHolder holder) {
    // Uncaching VH
    mBoundViewHolders.remove(holder);
}

// Your method becomes
public void updateVisibility(int visibility) {
    mVisibility = visibility;
    for (AbstractViewHolder holder : mBoundViewHolders) {
        holder.updateVisibility(visibility);
    }
}

Реализуйте свой интерфейс или абстрактный ViewHolder, чтобы вы могли вызывать свой метод. Таким образом, у вас есть доступ к вашему содержимому ViewHolder.


Это то, что я делаю в моем FlexibleAdapter, чтобы отменить notifyItemRangeChanged() элементов без вызова notifyItemRangeChanged(). И если у пользователя есть анимация, все выполняются, плюс фон также меняется, когда я toggleActivation() свой метод toggleActivation().

Если вы знаете лучший способ восстановить всю связанную VH, дайте мне знать.

Ответ 4

Все существующие представления - это те, которые видны, плюс некоторые представления, кэшированные RecyclerView. Вы можете получить доступ ко всем видимым View следующим образом:

View child;
for (int i = 0; i < mRecycler.getChildCount(); i++) {
    child = mRecycler.getChildAt(i);
    //In case you need to access ViewHolder:
    mRecycler.getChildViewHolder(child);
}

Даже если вы получаете доступ к кешированным View, они еще не привязаны к данным, поэтому вы не будете знать, должна ли метка быть видимой или нет. Просто установите видимость метки оставшегося Views в onBindViewHolder.

Остальная часть View просто не существует, поэтому вы ничего не можете изменить о них, даже если для них одинаковое состояние видимости ярлыков.

Ответ 5

Все приведенные выше решения дают только видимые держатели, но на самом деле есть еще 2-3 держателя, которые связаны, но не видны. Чтобы получить их, самый простой и точный способ, который я могу придумать, чтобы получить все владельцы:

int lastBoundHolderPosition = -1;
int lastDetachedHolderPosition = -1;

public void onBindViewHolder(final MyViewHolder holder, int position) {
    lastBoundHolderPosition = position;
    //Your implementation
}
public void onViewDetachedFromWindow(MyViewHolder holder){
    lastDetachedHolderPosition = holder.holder.getAdapterPosition();
}

Если вы хотите, чтобы все адаптеры были видимыми (плюс Связано, но не видно):

if(lastDetachedHolderPosition == -1){
    for(pos = 0; pos <= lastDetachedHolderPosition; pos++){
        ViewHolder holder = (ViewHolder) mRecyclerView.findViewHolderForAdapterPosition(pos);
    }
}else{
    if(lastBoundHolderPosition > lastDetachedHolderPosition){ //Scroll down
        //get all the bound holders
        for(int pos = lastDetachedHolderPosition + 1; pos <= lastBoundHolderPosition; pos++){
            ViewHolder holder = (ViewHolder) mRecyclerView.findViewHolderForAdapterPosition(pos);
        }
    }else{ //Scroll up
        //get all the bound holders
        for(int pos = lastBoundHolderPosition ; pos <= lastDetachedHolderPosition-1; pos++){
            ViewHolder holder = (ViewHolder) mRecyclerView.findViewHolderForAdapterPosition(pos);
        }

    }
}