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

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 <code>null</code> since the new positions of views
     * are unknown until the layout is calculated.
     * <p>
     * This method checks only the children of RecyclerView. If the item at the given
     * <code>position</code> is not laid out, it <em>will not</em> create a new one.
     * <p>
     * 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 <code>position</code> 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);

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

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RecyclerViewViewHolder复用机制是其高效的一个特点,即每次滑动RecyclerView,不会创建新的ViewHolder,而是重复利用已经创建过的ViewHolder,以避免性能问题。然而,这种复用机制可能会产生一些问题,例如在更改字体颜色,有可能无法生效。这是为什么呢? 其实,ViewHolder复用机制的本质是重用View而不是ViewHolder,ViewHolder只是用来保存已经创建的View,以便快速访问。当滑动RecyclerView,如果ViewHolder已经存在,则会直接调用它的bind方法,将新的数据绑定到它的View上。如果ViewHolder不存在,则会调用其create方法来创建ViewHolder和View。这些已经被创建的View将被存储在RecyclerView的内存池中,以供下一次调用重用。 因此,在更改字体颜色,可能由于ViewHolder和View已经被创建过,但其颜色设置仍然保留在内存池中,这导致新的颜色设置被覆盖或无法生效。为了解决这个问题,我们可以在bind方法中显式地更改字体颜色,以确保它被正确更新。同,我们需要确保每次ViewHolder复用都正确地更新所有的View。这就需要我们在创建ViewHolder,对所有的View进行初始化,确保每个View的颜色都被正确设置。 综上所述,我们需要在bind方法中显式地更改字体颜色,并在ViewHolder创建对所有View进行正确的初始化,以确保RecyclerViewViewHolder复用机制不会导致更改字体颜色失效的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值