FindViewHolderForPosition возвращает ноль, когда карты не видно

1

Я использую RecyclerView с CardView для отображения списка карт. Каждая карта имеет 2 linearLayout (1 для заголовка и 1 для разворота, вторая - только при нажатии карты).

Когда я изменяю приоритет карты, карта перемещается в новую позицию списка (я изменяю ее позицию в "массиве" элемента, а затем вызываю адаптер .notifyItemMoved(oldPosition, newPosition)), и он Я также называю RecyclerView.scrollToPosition(newPosition), чтобы показать новую позицию в списке.

Теперь проблема, я хочу развернуть карту после того, как я переместил ее в новую позицию, и для этого мне нужна линейная линейка внутри карты, они находятся в ViewHolder, которые держат карту. Я пытаюсь использовать RecyclerView.findViewHolderAtPosition(newPosition), но он возвращает ViewHolder только в том случае, если карта видна там, где я был до "scrollTo", если карта выведена из этих "видимых карт", она всегда возвращает null. (Я также использую mRecyclerView.setItemViewCacheSize(myDataset.size()) для решения других проблем, поэтому я ожидал правильного ViewHolder, даже если он не в зрении)

public void moveTask(int oldPosition, int position, Task task) {
    if (oldPosition < position) {
        myDataset.add(position, task);
        myDataset.remove(oldPosition);
    } else {
        myDataset.remove(oldPosition);
        myDataset.add(position, task);
    }
    mAdapter.notifyItemMoved(oldPosition, position);
    mAdapter.notifyDataSetChanged();
    mRecyclerView.smoothScrollToPosition(position);
    MyViewHolder holder =(MyViewHolder)mRecyclerView.findViewHolderForPosition(position);
    mAdapter.expandCard(holder);
}

mAdapter.notifyDataSetChanged() не следует вызывать (notifyItemMoved должно быть достаточно), но иногда это не работает без него.

expandCard просто устанавливает видимость линейного расширения "expandable" в Visible, а другой linearLayout "расширяемый" уже доступен для Gone.

Что я могу сделать, чтобы это сработало? Я делаю это совершенно неправильно? Надеюсь, я объяснил проблему понятным образом. Если мне нужно лучше объяснить, как я что-то делаю, я всегда здесь, спасибо за помощь.

  • 0
    У меня точно такая же ситуация.
Теги:
android-recyclerview

2 ответа

1
Лучший ответ

Итак, я решил это, я думал не так.

Вы не должны пытаться найти правильный ViewHolder из "снаружи", как я делал, а просто "развернуть" его в OnBindViewHolder, когда одна привязка является правильной.

В moveTask, который я делал, я делал это раньше, но я устанавливаю позицию открываемой карты:

public void moveTask(int oldPosition, int position, Task task) {
    if (oldPosition < position) {
        myDataset.add(position, task);
        myDataset.remove(oldPosition);
    } else {
        myDataset.remove(oldPosition);
        myDataset.add(position, task);
    }
    mAdapter.notifyItemMoved(oldPosition, position);
    //this is the important line, it set the variable
    //openPos with the right number
    mAdapter.setOpenPos(position);

    mAdapter.notifyItemChanged(position);
    mRecyclerView.scrollToPosition(position);
}

а затем в адаптере onBindViewHolder я проверяю, когда я нахожусь в правильном положении:

@Override
public void onBindViewHolder(MyViewHolder holder, int pos) {
    --set other fields--
    // expand the right card
    // if it the first open it
    if (pos == 0) {
        holder.expand(holder.mHeader, holder.mExpanded);
        // and collapse the opened one
        if (openPos != -1 && openPos != pos) {
            open.collapse(open.mHeader, open.mExpanded, true);
        }
        isFirst = holder;
        open = holder;
        openPos = 0;
    } 
     // I'm in the position of the one I should open
     // expand it
     else if (openPos != -1 && pos == openPos) {
        holder.expand(holder.mHeader, holder.mExpanded);
        // and if I changed openPos with setOpenPos()
        // collapse the "old" open card
        if(openPos != open.getPosition()){
            open.collapse(open.mHeader, open.mExpanded, true);
        }
        open = holder;
    }
     // if I'm in another card just collapse it 
     else {
        holder.collapse(holder.mHeader, holder.mExpanded, true);
    }

}

И, как это, отлично работает. Он должен работать даже без использования "setItemViewCacheSize", но у него есть другие странные проблемы без него, поэтому на данный момент я его оставляю.

0

Прежде всего, вы не должны называть mRecyclerView.setItemViewCacheSize(myDataset.size()). Это означает создание ViewHolder для каждого элемента в списке, не сильно отличающегося от использования LinearLayout.

Во-вторых, findViewHolderForPosition проверяет только детей. Это будет добавлено в документы для уточнения.

В вашем случае mAdapter.notifyItemMoved достаточно не, потому что RV не знает, что он должен переподчинить элемент. Вам также нужно вызвать notifyItemChanged, чтобы RV знал, что представление должно быть отскоком.

Создайте два типа представления (для простоты вам не обязательно). Один рухнул, один расширился. Затем, когда вы хотите переместить и развернуть элемент, вызовите:

public void moveTask(int oldPosition, int position, Task task) {
    if (oldPosition < position) {
        myDataset.add(position, task);
        myDataset.remove(oldPosition);
    } else {
        myDataset.remove(oldPosition);
        myDataset.add(position, task);
    }
    task.expanded = true;
    mAdapter.notifyItemMoved(oldPosition, position);
    mAdapter.notifyItemChanged(position);
}

//adapter
getItemViewType(int position) {
    return myDataset.get(position).expanded ? TYPE_EXPANDED : TYPE_HEADER;
}

Поскольку вы вызвали notifyItemChanged, RV перекроет это представление.

  • 0
    Я знаю, что не должен вызывать setItemViewCacheSize, но без него у нас возникают некоторые странные проблемы, например, если я разверну первую карту и прокручиву вниз, 12-я (в моем телефоне, 14-я в другом телефоне) также будет расширена. Я не уверен, как использовать два типа представлений, как вы предлагали, потому что я использую аниматор для анимации перехода: private void expand (заголовок LinearLayout, расширенный RelativeLayout) {extended.setVisibility (View.VISIBLE); ... ValueAnimator animator = slideAnimator (header.getMeasuredHeight (), extended.getMeasuredHeight (), расширенный); animator.start (); }

Ещё вопросы

Сообщество Overcoder
Наверх
Меню