为啥 RecyclerView 项目在点击两次后才改变背景颜色?
Posted
技术标签:
【中文标题】为啥 RecyclerView 项目在点击两次后才改变背景颜色?【英文标题】:Why does the RecyclerView item only change background color after clicking on it twice?为什么 RecyclerView 项目在点击两次后才改变背景颜色? 【发布时间】:2021-04-01 23:25:20 【问题描述】:我一直在探索 Recyclerview 和 Cardview,但偶然发现了一个我不知道如何处理的问题。我的 recyclerview 工作正常,但是当我让 recyclerview 的项目背景在点击时更改颜色时,它的行为很奇怪。
好的,recyclerview 加载正常,但是当我第一次单击某个项目时,项目背景颜色会闪烁其新颜色,但随后会保持其默认颜色。当我第二次单击任何项目时,recyclerview 的项目才会更改其背景颜色,因为它应该与单击的其余项目一起。
从我添加到代码中的Log.d
中,我发现第一次点击与第二次(以及其他)点击的不同之处在于PremiseAdapter
类中的公共PremiseAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
。我发现了一个与我的问题类似的question,但我认为我的代码不是这样工作的。
日志如下。
-
加载 recyclerview 及其 Cardview 项
.... D/rcvTest: PremiseAdapter.PremiseAdapter
.... D/rcvTest: PremiseAdapter.getItemCount
.... D/rcvTest: PremiseAdapter.getItemCount
.... D/rcvTest: ---------------------> PremiseAdapter.ViewHolder.onCreateViewHolder
.... D/rcvTest: [ViewHolder].ViewHolder.TOP
.... D/rcvTest: PremiseAdapter.onBindViewHolder
.... D/rcvTest: [ViewHolder].bindTo.TOP: FroyYo Mart
.... D/rcvTest: [ViewHolder].bindTo.BOTTOM FroyYo Mart
.... D/rcvTest: PremiseAdapter.onBindViewHolder.get(position)
.... D/rcvTest: PremiseAdapter.getItemCount
.... D/rcvTest: ---------------------> PremiseAdapter.ViewHolder.onCreateViewHolder
.... D/rcvTest: [ViewHolder].ViewHolder.TOP
.... D/rcvTest: PremiseAdapter.onBindViewHolder
.... D/rcvTest: [ViewHolder].bindTo.TOP: Ice Cream Store
.... D/rcvTest: [ViewHolder].bindTo.BOTTOM Ice Cream Store
.... D/rcvTest: PremiseAdapter.onBindViewHolder.get(position)
-
首先点击项目
.... D/rcvTest: [ViewHolder].ViewHolder.listener: null
.... D/rcvTest: [ViewHolder].ViewHolder.getAdapterPosition(): 1
.... D/rcvTest: [ViewHolder].ViewHolder.position: 1
.... D/rcvTest: getLayoutPosition(): 1
.... D/rcvTest: [ViewHolder].ViewHolder.position != RecyclerView.NO_POSITION
.... D/rcvTest: PremiseAdapter.getItemCount
.... D/rcvTest: PremiseAdapter.getItemCount
.... D/rcvTest: ---------------------> PremiseAdapter.ViewHolder.onCreateViewHolder
.... D/rcvTest: [ViewHolder].ViewHolder.TOP
.... D/rcvTest: PremiseAdapter.onBindViewHolder
.... D/rcvTest: [ViewHolder].bindTo.TOP: Ice Cream Store
.... D/rcvTest: [ViewHolder].bindTo.BOTTOM Ice Cream Store
.... D/rcvTest: PremiseAdapter.onBindViewHolder.get(position)
-
第二次(以及其他)点击项目
.... D/rcvTest: [ViewHolder].ViewHolder.listener: null
.... D/rcvTest: [ViewHolder].ViewHolder.getAdapterPosition(): 0
.... D/rcvTest: [ViewHolder].ViewHolder.position: 0
.... D/rcvTest: getLayoutPosition(): 0
.... D/rcvTest: [ViewHolder].ViewHolder.position != RecyclerView.NO_POSITION
.... D/rcvTest: PremiseAdapter.getItemCount
.... D/rcvTest: PremiseAdapter.getItemCount
.... D/rcvTest: PremiseAdapter.onBindViewHolder
.... D/rcvTest: [ViewHolder].bindTo.TOP: FroyYo Mart
.... D/rcvTest: [ViewHolder].bindTo.BOTTOM FroyYo Mart
.... D/rcvTest: PremiseAdapter.onBindViewHolder.get(position)
.... D/rcvTest: PremiseAdapter.getItemCount
这是我的PremiseAdapter.java
文件,其中包含我的PremiseAdapter
类和ViewHolder
类。
public class PremiseAdapter extends RecyclerView.Adapter<PremiseAdapter.ViewHolder>
private ArrayList<Premise> mPremiseData;
private Context context;
private int selected_position = -1;
OnItemClickListener onItemClickListener;
public interface OnItemClickListener
void onItemClick(int position);
public void setOnItemClickListener(OnItemClickListener itemClickListener)
onItemClickListener = itemClickListener;
public PremiseAdapter(Context context, ArrayList<Premise> mPremiseData)
Log.d("rcvTest", "PremiseAdapter.PremiseAdapter");
this.mPremiseData = mPremiseData;
this.context = context;
//Required method for creating the viewholder objects.
@NonNull
@Override
public PremiseAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
Log.d("rcvTest", "---------------------> PremiseAdapter.ViewHolder.onCreateViewHolder");
return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.list_premises, parent, false), onItemClickListener);
//Required method that binds the data to the viewholder.
@Override
public void onBindViewHolder(@NonNull PremiseAdapter.ViewHolder holder, int position)
// Get current premise.
// Populate the textviews with data.
@Override
public int getItemCount()
Log.d("rcvTest", "PremiseAdapter.getItemCount");
return mPremiseData.size();
/*----------------------------------- CLASS VIEWHOLDER -------------------------------------------*/
/*----------------------------------- CLASS VIEWHOLDER -------------------------------------------*/
/*class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener */
class ViewHolder extends RecyclerView.ViewHolder
// Member Variables for the TextViews
//Constructor for the ViewHolder, used in onCreateViewHolder().
ViewHolder(@NonNull View itemView, OnItemClickListener listener)
super(itemView);
cardView = itemView.findViewById(R.id.cardview_premise);
Log.d("rcvTest", "[ViewHolder].ViewHolder.TOP");
// Initialize the views.
// Set the OnClickListener to the entire view.
int clickedColor = Color.parseColor("#D5F5E3");
itemView.setOnClickListener((v) ->
int position = getAdapterPosition();
Log.d("rcvTest", "[ViewHolder].ViewHolder.listener: " + listener);
Log.d("rcvTest", "[ViewHolder].ViewHolder.getAdapterPosition(): " + getAdapterPosition());
Log.d("rcvTest", "[ViewHolder].ViewHolder.position: " + position);
Log.d("rcvTest", "getLayoutPosition(): " + getLayoutPosition());
if (position != RecyclerView.NO_POSITION)
Log.d("rcvTest", "[ViewHolder].ViewHolder.position != RecyclerView.NO_POSITION");
itemView.setBackgroundColor(clickedColor);
else if (position == RecyclerView.NO_POSITION)
Log.d("rcvTest", "[ViewHolder].ViewHolder.position == RecyclerView.NO_POSITION");
itemView.setBackgroundColor(clickedColor);
notifyItemChanged(position);
notifyItemChanged(getLayoutPosition());
);
void bindTo(Premise currentPremise)
// Populate the textviews with data.
Log.d("rcvTest", "[ViewHolder].bindTo.TOP: " + currentPremise.getPremiseName());
【问题讨论】:
【参考方案1】:我通常在 onbindviewholder 中实现 onclick 侦听器,它们似乎工作正常。我建议你应该尝试一下。 把这段代码移到onbindviewholder
int clickedColor = Color.parseColor("#D5F5E3");
/*itemView.setBackgroundColor(defaultColor);*/
holder.itemView.setOnClickListener((v) ->
int position = getAdapterPosition();
Log.d("rcvTest", "[ViewHolder].ViewHolder.listener: " + listener);
Log.d("rcvTest", "[ViewHolder].ViewHolder.getAdapterPosition(): " + getAdapterPosition());
Log.d("rcvTest", "[ViewHolder].ViewHolder.position: " + position);
Log.d("rcvTest", "getLayoutPosition(): " + getLayoutPosition());
if (position != RecyclerView.NO_POSITION)
Log.d("rcvTest", "[ViewHolder].ViewHolder.position != RecyclerView.NO_POSITION");
/*listener.onItemClick(position);*/
itemView.setBackgroundColor(clickedColor);
else if (position == RecyclerView.NO_POSITION)
Log.d("rcvTest", "[ViewHolder].ViewHolder.position == RecyclerView.NO_POSITION");
itemView.setBackgroundColor(clickedColor);
notifyItemChanged(position);
position = getLayoutPosition();
notifyItemChanged(position); //duplicate
);
只要确保改变
itemView.setOnClickListener(...) to holder.itemView.setOnClickListener(...)
【讨论】:
具体改成holder.itemView
。
@PrinceAli 是的,当然【参考方案2】:
试试这个。最近我有这个代码,它工作正常,希望它也能解决你的问题。
int row_index = -1;
holder.itemView.setOnClickListener(v ->
row_index = position;
notifyDataSetChanged();
);
if (row_index == position)
holder.layout.setBackgroundColor(Color.parseColor("#ff6600"));
else
holder.layout.setBackgroundColor(Color.parseColor("#ffffff"));
【讨论】:
感谢您的回答。我可以知道我应该在哪里实施吗?我拥有的类似代码存储在ViewHolder
类的ViewHolder(@NonNull View itemView, OnItemClickListener listener)
中,但我没有holder
。
感谢 Price Ali 为他解释代码。抱歉,阿里向您解释了迟到的回复。
@AtresJuni row_index 是全局变量,并将剩余代码添加到 onBindViewHolder。 (holder.layout) 是要添加背景颜色的根布局。
这行得通!我将notifyDataSetChanged();
更改为notifyItemChanged(position);
,这样当我单击另一个项目时颜色保持不变。但为什么会这样呢?
确定!但在此之前,你能解释一下为什么notifyDataSetChanged()
产生与notifyItemChanged(position)
不同的结果@ahmadbajwa以上是关于为啥 RecyclerView 项目在点击两次后才改变背景颜色?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我用jQuery写好checkbox的全选后,点击两次后,就不行了,要刷新页面后,点击才有响应,源码是这样