当卡片不在视觉中时,FindViewHolderForPosition返回null

时间:2014-12-22 12:45:14

标签: android android-recyclerview

我使用RecyclerView和CardView显示卡片列表。每张卡都有2个linearLayout(标题为1,扩展为1,第二张只有在按下卡时才可见)。

当我修改卡片的优先级时,卡片会移动到列表的新位置(我更改它在"阵列中的位置"项目,然后调用适配器。 notifyItemMoved(oldPosition,newPosition))它工作正常,我还调用了RecyclerView.scrollToPosition(newPosition)来显示列表中的新位置。

现在问题是,我想在我将它移动到新位置后扩展卡并且这样做我需要卡内的linearLayout,它们位于持有卡的ViewHolder中。我试图使用RecyclerView.findViewHolderAtPosition(newPosition),但只有当卡片显示在" scrollTo"之前我看到的地方时才返回ViewHolder,如果卡片被移出这些&# 34;可见卡"它总是返回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只是设置了linearLayout的可见性&#34;可扩展&#34;可见和其他linearLayout&#34;可扩展&#34;已经可见了。

我能做些什么让它有效?我完全错了吗? 我希望我以一种易于理解的方式解释了这个问题。如果我需要更好地解释我在做什么,我总是在这里,谢谢你的帮助。

2 个答案:

答案 0 :(得分: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's 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”的情况下工作,但是如果没有它就会有其它奇怪的问题,所以现在我就把它留下来。

答案 1 :(得分: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将重新绑定该视图。