在RecyclerView中更改所选项目的背景颜色

83
如何在我的recycle view示例中仅更改所选视图的背景颜色?只需要更改所单击的itemview的背景颜色。 一次只显示一个选定的项目,并且其余项目在选择之前必须保持原样。 以下是我的代码:

MainActivity

public class MainActivity extends AppCompatActivity {
RecyclerView rv1;
    private  final String android_versions[]={
                "Donut",
                "Eclair",
                "Froyo",
                "Gingerbread",
                "Honeycomb",
                "Ice Cream Sandwich",
                "Jelly Bean",
                "KitKat",
                "Lollipop",
                "Marshmallow"
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
    }

    private  void initViews(){
        rv1=(RecyclerView)findViewById(R.id.recyclerView1);
        rv1.setHasFixedSize(true);
        RecyclerView.LayoutManager layoutManager=new LinearLayoutManager(getApplicationContext());
        rv1.setLayoutManager(layoutManager);

        RecyclerDataAdapter rda=new RecyclerDataAdapter(rv1,getApplicationContext(),android_versions);
        rv1.setAdapter(rda);
    }
}
RecyclerDataadapter
public class RecyclerDataAdapter extends RecyclerView.Adapter<RecyclerDataAdapter.ViewHolder> {

private String android_versionnames[];
    private Context context1;

    private RecyclerView mRecyclerView;


    public RecyclerDataAdapter(RecyclerView recylcerView,Context context,String android_versionnames[]){
        this.android_versionnames=android_versionnames;
        this.context1=context;
mRecyclerView=recylcerView;
        setHasStableIds(true);
        System.out.println("Inside dataadapter,Android names : \n ");
        for(int i=0;i<android_versionnames.length;i++){
            System.out.println("\n"+android_versionnames[i]);
        }
    }


    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.row_layout,parent,false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        holder.tv1.setText(android_versionnames[position]);
    }


    @Override
    public int getItemCount() {
        return android_versionnames.length;
    }


    public class ViewHolder extends RecyclerView.ViewHolder {
        private TextView tv1;
        LinearLayout row_linearlayout;
        RecyclerView rv2;

        public ViewHolder(final View itemView) {
            super(itemView);
            tv1=(TextView)itemView.findViewById(R.id.txtView1);
            row_linearlayout=(LinearLayout)itemView.findViewById(R.id.row_linrLayout);
            rv2=(RecyclerView)itemView.findViewById(R.id.recyclerView1);
            /*itemView.setBackgroundColor(0x00000000);//to transparent*/

        }
    }
}

更改 @drawable/shapecolored 的 @color 并添加形状。 - Paolo Rivera
23个回答

180

可能有改进空间,但它能正常工作。

int selectedPosition = -1;
int lastSelectedPosition = -1;
public void onBindViewHolder(final ViewHolder holder, final int position) {
  holder.binding.getRoot().setOnClickListener(v -> {
    lastSelectedPosition = selectedPosition;
    selectedPosition = holder.getBindingAdapterPosition();
    notifyItemChanged(lastSelectedPosition);
    notifyItemChanged(selectedPosition);
  });
  if (selectedPosition == holder.getBindingAdapterPosition()) {
    holder.binding.linearLayout.setCardBackgroundColor(Color.LTGRAY);
  } else {
    holder.binding.linearLayout.setCardBackgroundColor(Color.WHITE);
  }

}

public class ViewHolder extends RecyclerView.ViewHolder {
  ItemBinding binding;

  public ViewHolder(ItemBinding binding) {
    super(binding.getRoot());
    this.binding = binding;
  }
}


1
兄弟,代码完美运行,但是当我改变颜色时出现了错误,例如(0索引文本(蓝色)1索引文本(黑色)),当我改变为黑色时,它会转移到蓝色,你能帮我吗? - MustafaShaikh
1
我们如何更改未选中项目的颜色? - Ranjith Kumar
3
在onBindViewHolder内每次创建新的OnClickListener并不是一个很好的主意。 - Prateek Gupta

14

一个非常简单的实现方法是:

//instance variable
List<View>itemViewList = new ArrayList<>();

//OnCreateViewHolderMethod
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {    
    final View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_row, parent, false);
    final MyViewHolder myViewHolder = new MyViewHolder(itemView);

    itemViewList.add(itemView); //to add all the 'list row item' views

    //Set on click listener for each item view
    itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            for(View tempItemView : itemViewList) {
                /** navigate through all the itemViews and change color
                of selected view to colorSelected and rest of the views to colorDefault **/
                if(itemViewList.get(myViewHolder.getAdapterPosition()) == tempItemView) {
                    tempItemView.setBackgroundResource(R.color.colorSelected);
                }
                else{
                    tempItemView.setBackgroundResource(R.color.colorDefault);
                }
            }
        }
    });
    return myViewHolder;
}

更新

上述方法可能会破坏itemView的一些默认属性,在我的情况下,我正在使用CardView,并且点击时卡片的圆角被删除。

更好的解决方案:

//instance variable
List<CardView>cardViewList = new ArrayList<>();

public class MyViewHolder extends RecyclerView.ViewHolder {
        CardView cardView; //THIS IS MY ROOT VIEW
        ...

        public MyViewHolder(View view) {
            super(view);
            cardView = view.findViewById(R.id.row_item_card);
            ...
        }
}

@Override
    public void onBindViewHolder(final MyViewHolder holder, int position) {
        final OurLocationObject locationObject = locationsList.get(position);
        ...

        cardViewList.add(holder.cardView); //add all the cards to this list

        holder.cardView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //All card color is set to colorDefault
                for(CardView cardView : cardViewList){
                cardView.setCardBackgroundColor(context.getResources().getColor(R.color.colorDefault));
                }
                //The selected card is set to colorSelected
                holder.cardView.setCardBackgroundColor(context.getResources().getColor(R.color.colorSelected));
            }
        });
}

更新2 - 重要

onBindViewHolder方法会被多次调用,而且每当用户将视图滚出视线并再次滚回时都会调用此方法! 这将导致同一视图被多次添加到列表中,可能会在代码执行上造成问题和轻微的延迟!

为了解决这个问题, 请更改

cardViewList.add(holder.cardView);

if (!cardViewList.contains(holder.cardView)) {
    cardViewList.add(holder.cardView);
}

7
我可以提供一个解决方案,这是我在我的应用程序中使用的。我将这个OnTouchListener代码放在我的ViewHolder类的构造函数中。itemView是构造函数的参数。一定要在此方法上使用return false,因为这需要工作OnClickListener。
itemView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN)
        {
            v.setBackgroundColor(Color.parseColor("#f0f0f0"));
        }
        if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL)
        {
            v.setBackgroundColor(Color.TRANSPARENT);
        }
        return false;
    }
});

1
帮助维持按下状态。 - Jaswanth Manigundan

5
在Drawable文件夹中创建可绘制文件。
<item android:drawable="@color/SelectedColor" android:state_pressed="true"></item>
<item android:drawable="@color/SelectedColor" android:state_selected="true"></item>
<item android:drawable="@color/DefultColor"></item>

在XML文件中:

android:background="@drawable/Drawable file"

在RecyclerView的onBindViewHolder方法中,
holder.button.setSelected(holder.button.isSelected()?true:false);

像切换按钮一样


什么是prob?告诉我一下,Anvi。 - Joy
2
@Joy 这只会让颜色短暂变化。 - TDG
这应该是其他关于使项目看起来像被点击的帖子的答案! - JPM
@TDG 在 onClick 中添加 android:state_activated="true" 和将 android:state_selected 都设置为 true 可能会有帮助。 - Ronnie

4
我能够像这样更改选择视图的颜色。我认为这是最简单的方法(因为您不必创建布局和变量的实例)。
确保您不在RecyclerView的标签内赋予任何背景颜色。
holder.itemView.setBackgroundColor(Color.parseColor("#8DFFFFFF"));

下面给出了onBindViewHolder()方法的代码:
@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {

        holder.item_1.setText(list_items.get(position).item_1);
        holder.item_2.setText(list_items.get(position).item_2);
        holder.select_cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

                if (isChecked){

                    holder.itemView.setBackgroundColor(Color.parseColor("#8DFFFFFF"));
                }else {

                    holder.itemView.setBackgroundColor(Color.parseColor("#FFFFFF"));
                }
            }
        });
}

2
我所做的是使用一个静态变量来存储RecyclerView中上次点击项目的位置,然后通知适配器在上次点击位置处更新布局,即当新位置被点击时调用notifyItemChanged(lastClickedPosition)。在整个布局上调用notifyDataSetChanged()非常昂贵且不可行,因此仅针对一个位置进行操作更加优秀。
以下是代码:
public class RecyclerDataAdapter extends RecyclerView.Adapter<RecyclerDataAdapter.ViewHolder> {

private String android_versionnames[];
private Context mContext;
private static lastClickedPosition = -1; // Variable to store the last clicked item position


    public RecyclerDataAdapter(Context context,String android_versionnames[]){
        this.android_versionnames = android_versionnames;
        this.mContext = context;
        }
    }


    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(mContext).inflate(R.layout.row_layout,
                parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        holder.tv1.setText(android_versionnames[position]);    
        holder.itemView.setBackgroundColor(mContext.getResources().
        getColor(R.color.cardview_light_background));
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {                    
            v.setBackgroundColor(mContext.getResources().
            getColor(R.color.dark_background));
                if (lastClickedPosition != -1)
                    notifyItemChanged(lastClickedPosition);
                lastClickedPosition = position;
            }
        });
    }


    @Override
    public int getItemCount() {
        return android_versionnames.length;
    }


    public class ViewHolder extends RecyclerView.ViewHolder {
        private TextView tv1;

        public ViewHolder(final View itemView) {
            super(itemView);
            tv1=(TextView)itemView.findViewById(R.id.txtView1);
        }
    }
}

因此,我们只会更新预期的项目,而不会对甚至未更改的项目重新运行不必要的更新。

2
如果你使用Kotlin,这非常简单。
在你的RecyclerAdapter类中:
userV.invalidateRecycler()

holder.card_User.setCardBackgroundColor(Color.parseColor("#3eb1ae").withAlpha(60))

最初的回答:在你的碎片或活动中
在你的碎片或活动中,
 override fun invalidateRecycler() {
    if (v1.recyclerCompanies.childCount > 0) {
        v1.recyclerCompanies.childrenRecursiveSequence().iterator().forEach { card ->
            if (card is CardView) {
                card.setCardBackgroundColor(Color.WHITE)
            }
        }
    }
}

2

这个问题有一个非常简单的解决方案,你不需要在适配器中工作。要更改RecyclerView中已点击项的背景,您需要使用接口在适配器中捕获单击事件:

interface ItemClickListener {
    fun onItemClickListener(item: Item, position: Int)
}

当我们点击时,会获取该项和该项的位置。在适配器中的绑定函数中,我们将设置点击监听器:

container.setOnClickListener {
    onClickListener.onItemClickListener(item, position)
}

在您的活动中,您将实现此接口:
class MainActivity : AppCompatActivity(), ItemAdapter.ItemClickListener {

接下来,我们需要在项目点击时实现背景色的更改逻辑。逻辑如下:当用户单击一个项目时,我们检查被单击项目的背景是否为白色(即该项目以前未被单击),如果此条件成立,则将 RecyclerView 中所有项目的背景更改为白色(以使先前单击和标记的项目无效,如果有的话),然后将单击项目的背景颜色更改为深绿色以进行标记。如果单击项目的背景为深绿色(这意味着用户再次单击了相同的先前标记项目),我们将所有项目的背景颜色更改为白色。首先,我们需要将项目背景颜色作为 ColorDrawable 获取。我们将使用迭代器函数遍历 RecyclerView 的所有项目(子项),并使用 forEach() 函数更改它们中的每一个的背景。此方法如下所示:

 override fun onItemClickListener(item: Item, position: Int) {
        val itemBackground: ColorDrawable =
            binding.recycler[position].background as ColorDrawable
        if (itemBackground.color == ContextCompat.getColor(this, R.color.white)) {
            binding.recycler.children.iterator().forEach { item ->
                item.setBackgroundColor(
                    ContextCompat.getColor(
                        this,
                        R.color.white
                    )
                )
            }
            binding.recycler[position].setBackgroundColor(
                ContextCompat.getColor(this, R.color.teal_200)
            )
        } else {
            binding.recycler.children.iterator().forEach { item ->
                item.setBackgroundColor(
                    ContextCompat.getColor(
                        this,
                        R.color.white
                    )
                )
            }
        }
    }

现在,您可以在单击项目时更改背景,如果您再次单击相同的项目,则会将背景更改回之前的状态。


1

当你需要改变一个项目时,调用Notifydatasetchanged可能会很昂贵。我们可以通过保存旧位置并调用notifyItemChanged来克服这个问题。

var old_postion=-1

   public void onBindViewHolder(final ViewHolder holder, final int position) {
    holder.tv1.setText(android_versionnames[position]);

    holder.row_linearlayout.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
       
            notifyItemChanged(old_position)
           //After item change happens set the old_postion as current position
            old_position=position
        }
    });
    if(old_position==position){
        holder.row_linearlayout.setBackgroundColor(Color.parseColor("#567845"));
        holder.tv1.setTextColor(Color.parseColor("#ffffff"));
    }
    else
    {
        holder.row_linearlayout.setBackgroundColor(Color.parseColor("#ffffff"));
        holder.tv1.setTextColor(Color.parseColor("#000000"));
    }

}

1
我的解决方案:
public static class SimpleItemRecyclerViewAdapter
        extends RecyclerView.Adapter<SimpleItemRecyclerViewAdapter.ViewHolder> {

    private final MainActivity mParentActivity;
    private final List<DummyContent.DummyItem> mValues;
    private final boolean mTwoPane;
    private static int lastClickedPosition=-1;
    **private static View viewOld=null;**
    private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            DummyContent.DummyItem item = (DummyContent.DummyItem) view.getTag();
            if (mTwoPane) {
                Bundle arguments = new Bundle();
                arguments.putString(ItemDetailFragment.ARG_ITEM_ID, item.id);
                ItemDetailFragment fragment = new ItemDetailFragment();
                fragment.setArguments(arguments);
                mParentActivity.getSupportFragmentManager().beginTransaction()
                        .replace(R.id.item_detail_container, fragment)
                        .commit();
            } else {
                Context context = view.getContext();
                Intent intent = new Intent(context, ItemDetailActivity.class);
                intent.putExtra(ItemDetailFragment.ARG_ITEM_ID, item.id);

                context.startActivity(intent);
            }

            **view.setBackgroundColor(mParentActivity.getResources().getColor(R.color.SelectedColor));
            if(viewOld!=null)
                viewOld.setBackgroundColor(mParentActivity.getResources().getColor(R.color.DefaultColor));
            viewOld=view;**
        }
    };

viewOld在开始时为null,然后指向最后选择的视图。 使用onClick更改所选视图的背景,并重新定义上一个选择的视图的背景。 简单而实用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接