RecyclerView - 当未调用onBindViewHolder时,findViewHolderForPosition始终返回null

时间:2015-04-05 15:22:10

标签: android android-layout android-recyclerview

我一直在尝试使用新的RecyclerView窗口小部件几天,并且我认为我已经设法创建了一个水平和网格布局,并且还克服了它缺乏直接方式的事实实现一个OnClickListener(我使用了GreenRobot's EventBus),我仍然很难在整个回收过程中选择一个项目并保留该状态(样式)。

这是我用于我的适配器的代码

public class ArticuloItemAdapter extends RecyclerView.Adapter<ArticuloItemAdapter.ItemHolder> {
    private ArrayList<ArticuloObject> mItems;
    private LayoutInflater mLayoutInflater;
    private int mSize;
    private int mSelectedPosition;
    private RecyclerView mRecyclerView;

    public ArticuloItemAdapter(Context context, RecyclerView rv, ArrayList<ArticuloObject> articulos) {

        mLayoutInflater = LayoutInflater.from(context);
        mItems=articulos ;     
        mSize = context.getResources()
                .getDimensionPixelSize(R.dimen.icon);
        mSelectedPosition = -1;
        mRecyclerView = rv;
    }

    @Override
    public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = mLayoutInflater.inflate(R.layout.gallery_recycler_row, parent, false);
        return new ItemHolder(itemView, this);
    }

    @Override
    public void onBindViewHolder(ItemHolder holder, int position) {      
        Ion.with(holder.getPicImageView())
                .placeholder(R.drawable.owner_placeholder)
                .resize(mSize, mSize)
                .centerCrop()
                .error(R.drawable.owner_error)
                .load(mItems.get(position).getUrl());

        //Update the views as they got recycled
        if (mSelectedPosition != position) {
            holder.getPicImageView().setBackgroundColor(Color.TRANSPARENT);
        } else {
            holder.getPicImageView().setBackgroundColor(Color.CYAN);
        }
    }

    @Override
    public int getItemCount() {
        return mItems.size();
    }

    public int getSelectedPosition() {
        return mSelectedPosition;
    }

    public void setSelectedPosition(int mSelectedPosition) {
        this.mSelectedPosition = mSelectedPosition;
    }

    public RecyclerView getRecyclerView() {
        return mRecyclerView;
    }

    /* Required implementation of ViewHolder to wrap item view */
    public class ItemHolder extends RecyclerView.ViewHolder implements
            View.OnClickListener {
        private ArticuloItemAdapter mParent;
        private ImageView mPicImageView;

        public ItemHolder(View itemView, ArticuloItemAdapter parent) {
            super(itemView);
            itemView.setOnClickListener(this);

            mParent = parent;

            mPicImageView = (ImageView) itemView.findViewById(R.id.picture_image_view);
        }

        public ImageView getPicImageView() {
            return mPicImageView;
        }

        @Override
        public void onClick(View v) {
            EventBus.getDefault().post(new OnArticuloCartaClickEvent(this, getPosition()));
            setItemActivated(v);
        }

        public void setItemActivated(View v) {

            //Check position of previous selected item. The first time an item is selected, the previous position will be  -1
            if (mParent.getSelectedPosition() >= 0) { 
                ItemHolder row = (ItemHolder) mParent.getRecyclerView().findViewHolderForPosition(mParent.getSelectedPosition());
                if (row != null) {
                    row.getPicImageView().setBackgroundColor(Color.TRANSPARENT);
                }
            }
            mParent.setSelectedPosition(getPosition());
            v.findViewById(R.id.picture_image_view).setBackgroundColor(Color.CYAN);

        }
    }

}

现在在上面显示的代码中,我正在做的所有跟踪所选项目的内容如下:

予。在onClick(View v)事件中:

  1. 每当点击一个项目时,我都会调用setItemActivated方法
  2. 在setItemActivated方法中,我检查selectedPosition是否大于或等于0(当没有选择项目时,默认值为-1)。
  3. 如果之前的条件为真,我会尝试将ViewHolder放在该位置,如果该视图不为空,我会将ImageView的背景颜色更改回原始背景颜色(透明) )
  4. 使用getPosition()
  5. 将mSelectedPosition的新值设置为当前位置
  6. 最后,将当前ImageViewViewHolder的背景颜色更改为其他颜色(本例中为CYAN)
  7. II。在onBindViewHolder(ItemHolder holder,int position)方法中:

    如果所选项目(mSelectedPosition)的位置不同 正在显示的视图的位置,我改变了背景 ImageView的颜色恢复为默认颜色。 否则,我将ImageView的颜色更改为用于标识所选项目的颜色(CYAN)。

    只要RecyclerView具有开始回收视图所需的大量项目,所有这一切都有效。但如果没有,就像在我的情况下,我注意到findViewHolderForPosition总是返回null,因此,我无法将之前选择的项目的颜色更改回其默认颜色,所以我结束了选择了多个项目。

    enter image description here

    更糟糕的是,由于RecyclerView不需要回收任何东西,onBindViewHolder方法永远不会被调用,因此我不能指望里面的代码来调整颜色相应的项目。

    拜托,我真的很感激,如果有人能告诉我这里我做错了什么,或者提出一些想法。如果不能做一些像选择项目那样基本的东西,真的很令人沮丧。

    提前致谢。

1 个答案:

答案 0 :(得分:4)

这种情况正在发生,因为当所选项目发生变化时,您并没有告诉RecyclerView前一项目是否已失效。

不要尝试手动设置,而是执行以下操作:

public void setItemActivated(View v) {
   final int myPos = getAdapterPosition();
   if (myPos == RecyclerView.NO_POSITION) {
       // very rare case where item is clicked but its adapter position 
       // is unknown. ignore the event.
       // See docs of getAdapterPosition for details
   }
   final int prevSelected = mParent.getSelectedPosition();
   mParent.setSelectedPosition(myPos);
   if (prevSelected >= 0 && prevSelected < mParent.getItemCount()) {
       mParent.notifyItemChanged(prevSelected);
   }
   mParent.notifyItemChanged(myPos);
}

RecyclerView将调用onBind以获取应更新的视图。您不需要关心以前所选项目的位置。