Android 在不可操作时 获取Recyclerview的viewholder并动态改变view

应公司的需求,需要在没有触摸屏只有上下确定和取消的物理按键设备上操作Recyclerview并标记出当前选中栏(多一嘴,卧槽啊,搞毛啊,省预算也不是这么省的啊!不带触摸屏你用QT啊!QT效果不好?不带触摸屏加物理按键效果就好了?!),做的时候就想当然的在bindView里把holder添加到了集合里,然后根据上下键事件往下走改变view,然后,突然很傻比的发现忽略了最基本的事情,Recyclerview就只会在一开始创建当前屏幕显示数的holder,并不能获取到全部的holder,这样我在按下键的时候就只会走到当前显示的最后item上去,下面就再也走不动了。

好吧,开始找方法,大体思路就是动态的来获取holder改变布局,但是我需要在外面的物理按键回调里改变Recyclerview里面的view,嗯,一开始还就创建几个,后面的就不能再onBind里拿到了,再看看有没有什么其他方法,看见一个,getChildViewHolder(View child),嗯,看方法名很靠谱,但是参数是view。。。。

好吧,只能进去看看代码了,从上到下翻了一圈,发觉有一个方法

    /**
     * Return the ViewHolder for the item in the given position of the data set. Unlike
     * {@link #findViewHolderForLayoutPosition(int)} this method takes into account any pending
     * adapter changes that may not be reflected to the layout yet. On the other hand, if
     * {@link Adapter#notifyDataSetChanged()} has been called but the new layout has not been
     * calculated yet, this method will return null since the new positions of views
     * are unknown until the layout is calculated.
     * 

* This method checks only the children of RecyclerView. If the item at the given * position is not laid out, it will not create a new one. *

* When the ItemAnimator is running a change animation, there might be 2 ViewHolders * representing the same Item. In this case, the updated ViewHolder will be returned. * * @param position The position of the item in the data set of the adapter * @return The ViewHolder at position or null if there is no such item */ public ViewHolder findViewHolderForAdapterPosition(int position) { if (mDataSetHasChangedAfterLayout) { return null; } final int childCount = mChildHelper.getUnfilteredChildCount(); // hidden VHs are not preferred but if that is the only one we find, we rather return it ViewHolder hidden = null; for (int i = 0; i < childCount; i++) { final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i)); if (holder != null && !holder.isRemoved() && getAdapterPositionFor(holder) == position) { if (mChildHelper.isHidden(holder.itemView)) { hidden = holder; } else { return holder; } } } return hidden; }

嗯,除了mDataSetHasChangedAfterLayout这个变量看起来有点辣眼,后面明显就可以获取到我所需要的holder啊,可以可以,来边走边试

rvPsytopicList.scrollToPosition(index);
RecyclerView.ViewHolder viewHolderForAdapterPosition = rvPsytopicList.findViewHolderForAdapterPosition(index);

先让它滑动到我所需要改变的item,更新holder,然后我获取holder该干嘛干嘛,嗯,简直天才。嗯?走到超出屏幕的下一条返回了个null?嗯?继续按走到最后再往上走就能获取到了?这玩意还有延迟不成?好吧。。再进去源码看吧。

for (int i = 0; i < childCount; i++) {
            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
            //这里循环检查已存在的holder
            if (holder != null && !holder.isRemoved() && getAdapterPositionFor(holder) == position) {
                if (mChildHelper.isHidden(holder.itemView)) {
                    hidden = holder;
                } else {
                    return holder;
                }
            }
        }

嗯。。。。。并没有找到为啥,但是看在以上循环检查的时候debug知道以前滚过的item的holder是有的,可以,这样这个需求的难度就是不存在的了兄弟~,立马改代码,让每次多scroll一个角标,成功实现!

rvPsytopicList.scrollToPosition(index+1);
RecyclerView.ViewHolder viewHolderForAdapterPosition = rvPsytopicList.findViewHolderForAdapterPosition(index);

(初来乍到,一脚踏入不知深浅,望多多指教!)

你可能感兴趣的:(Android 在不可操作时 获取Recyclerview的viewholder并动态改变view)