Skip to content Skip to sidebar Skip to footer

Findviewholderforposition Return Null When Card's Not In Vision

I'm using RecyclerView with CardView to display a list of Cards. Every card has 2 linearLayout (1 for the header, and 1 for the expand, the second one became visible only when the

Solution 1:

So I kinda resolved it, I was thinking in the wrong way.

You shouldn't try to find the right ViewHolder from "outside" like I was doing, but just "expand" it in the OnBindViewHolder when the one binding is the right one.

In the moveTask I do was I was doing before, but I set the position of the card to be opened:

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);
}

and then in the adapter's onBindViewHolder I check when I'm in the right position:

@Overridepublic void onBindViewHolder(MyViewHolder holder, int pos) {
    --set other fields--
    // expand the right card// if it's the first open itif (pos == 0) {
        holder.expand(holder.mHeader, holder.mExpanded);
        // and collapse the opened oneif (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 itelseif (openPos != -1 && pos == openPos) {
        holder.expand(holder.mHeader, holder.mExpanded);
        // and if I changed openPos with setOpenPos()// collapse the "old" open cardif(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);
    }

}

And like this it works fine. It should work even without the use of "setItemViewCacheSize", but it has other strange problems without it so for now I leave it.

Solution 2:

First of all, you should not call mRecyclerView.setItemViewCacheSize(myDataset.size()). It means creating a ViewHolder for each item in the list, not much different than use a LinearLayout.

Secondly, findViewHolderForPosition only checks the childrens. This will be added to docs for clarification.

In your case, mAdapter.notifyItemMoved is not enough because RV does not know it has to rebind the item. You also need to call notifyItemChanged so that RV knows the view should be rebound.

Create two view types (for simplicity, you dont have to). One collapsed, one expanded. Then when you want to move and expand the item, call:

publicvoidmoveTask(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;
}

Because you've called notifyItemChanged RV will rebind that view.

Post a Comment for "Findviewholderforposition Return Null When Card's Not In Vision"