首页 > 解决方案 > 如何通过 onClick 事件更改 RecyclerView 中的所有元素?

问题描述

我有一个RecyclerView每个元素都有一个onClickEventListener()可以改变它的外观的地方。它工作正常,但我实际上需要更改所有其他元素的外观。具体来说,我需要用颜色填充单击的元素,而其他元素应该只有描边。我认为有更优雅的方式来做到这一点,而不是遍历RecyclerView.
我当前的代码如下所示:

vh.mImageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            GradientDrawable typeShape = (GradientDrawable) vh.mImageView.getDrawable();
            if (vh.clicked) {
                typeShape.setColor(Color.parseColor("#00ff5800"));
            } else {
                typeShape.setColor(Color.parseColor("#ff5800"));
            }
            vh.clicked = !vh.clicked;
        }
    });

标签: javaandroid

解决方案


在我看来,做到这一点的“最佳”方法涉及使用大多数人不熟悉的 RecyclerView API 的一部分:例如notifyItemRangeChanged()接受有效负载对象的重载。

https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter#notifyitemrangechanged

当您传递一个有效负载对象时,onBindViewHolder()将调用一个特殊版本的有效负载,并将该有效负载传递给此方法。

https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#onbindviewholder_5

所有这一切让您做的是对任何显示的 ViewHolder 对象进行非常有效的重新绑定,并且只更新您知道已更改的视图部分。

在您的特定示例中,您可以让您的适配器跟踪selectedPosition并让您的onBindViewHolder()方法根据项目的位置是否等于当前选定的位置来设置项目的背景:

private void updateBackground(ViewHolder holder, int position) {
    holder.itemView.setBackgroundResource(
        (position == selectedPosition) ? R.drawable.highlight : R.drawable.stroke);
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    updateBackground(holder, position);
    // other view binding stuff
}

然后你也可以有一个特殊onBindViewHolder()调用的实现来做部分更新:

@Override
public void onBindViewHolder(ViewHolder holder, int position, List<Object> payloads) {
    if (payloads != null && payloads.contains("BACKGROUND")) {
        updateBackground(holder, position);
    }
}

一旦你设置了这两个,任何时候选择的位置发生变化,你都可以调用:

adapter.selectedPosition = 23; // or whatever else
adapter.notifyItemRangeChanged(0, adapter.getItemCount(), "BACKGROUND");

当您调用这个特殊版本时notifyItemRangeChanged(),系统将调用您的特殊版本onBindViewHolder(),您将有机会重新绘制所有当前可见视图的背景。但是您不会浪费时间更新任何当前不可见的视图,也不会浪费时间绑定根本没有更改的数据(所有来自 normaonBindViewHolder()实现的“其他视图绑定内容”)。


推荐阅读