This is the project我正试着跑。这是我在RecyclerView.Adapter类
中的onBindViewHolder的代码@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
TextView title = (TextView) holder.view.findViewById(R.id.title);
final TextView desc = (TextView) holder.view.findViewById(R.id.desc);
final ImageView imageView = (ImageView) holder.view.findViewById(R.id.imageView);
title.setText(pojos.get(position).getTitle());
desc.setText(pojos.get(position).getDesc());
imageView.setImageResource(pojos.get(position).getImage());
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
desc.setText("clicked");
desc.setBackgroundColor(Color.BLUE);
imageView.setImageResource(R.drawable.heart_red);
}
});
}
列表加载正常,调用imageView的onclicklistener时会出现问题。
desc.setText("clicked");
上面的行在单击它的列表项中进行更改。但是
desc.setBackgroundColor(Color.BLUE);
执行此行时,更改将反映在列表中的多个项目中。出了什么问题?在下面显示的图片中,我点击了第0项,文字变为"点击了"和颜色设置。但是当我向下滚动时,项目12也受到了我对项目0的点击的影响。仅反映了背景颜色变化,而不是文本更改。我该如何阻止它?
我一直试图解决这个问题很长时间,请下载项目并尝试执行代码以了解我的意思,如果我的问题不明确的话。
答案 0 :(得分:11)
这是因为视图被回收并重复使用。
因此,当视图被回收时,如果您不再次更改它,它将保留“旧”视图的属性。因此,当您向下滚动到数字12时,用于保存数字1的视图将被回收(因为它不再在屏幕上显示),并用于创建数字12.这就是为什么蓝色在数字上的原因12。
例如,当单击该项时,您需要将“单击”值保存到POJO对象中。然后在绘制项目时,检查该值并根据该值设置正确的图像/背景颜色。
我在下面的代码中完成了这个,所以它应该让你大致了解该怎么做:
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
TextView title = (TextView) holder.view.findViewById(R.id.title);
final TextView desc = (TextView) holder.view.findViewById(R.id.desc);
final ImageView imageView = (ImageView) holder.view.findViewById(R.id.imageView);
final MyPojo pojo = pojos.get(position);
title.setText(pojo.getTitle());
if(!pojo.clicked) {
desc.setText(pojo.getDesc());
imageView.setImageResource(pojo.getImage());
desc.setBackgroundColor(Color.argb(0,0,0,0));
} else {
desc.setText("clicked");
desc.setBackgroundColor(Color.BLUE);
imageView.setImageResource(R.drawable.heart_red);
}
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
pojo.clicked = true;
desc.setText("clicked");
desc.setBackgroundColor(Color.BLUE);
imageView.setImageResource(R.drawable.heart_red);
}
});
}
我在MyPojo类中添加了一个“clicked”布尔值。
public class MyPojo {
String title;
String desc;
int image;
boolean clicked;
}
答案 1 :(得分:7)
只需在getItemCount方法
之后在适配器类中添加一个方法@Override
public int getItemViewType(int position) {
return position;
}
它将解决问题
答案 2 :(得分:2)
通过在onBindViewHolder中调用findViewById,您似乎对使用RecyclerView感到困惑。这些昂贵的查找应该在onCreateViewHolder中进行,您可以在其中查找所有视图并将其引用保存到自定义视图持有者。我继续在github repo中查看你的代码并提出以下更改:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private ArrayList<MyPojo> pojos;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView title;
public TextView desc;
public ImageView imageView;
public ViewHolder(View v) {
super(v);
// all expensive findViewById lookups happen in ViewHolder constructor,
// which is called only when onCreateViewHolder is called
this.title = (TextView) v.findViewById(R.id.title);
this.desc = (TextView) v.findViewById(R.id.desc);
this.imageView = (ImageView) v.findViewById(R.id.imageView);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(ArrayList<MyPojo> pojos) {
this.pojos = pojos;
}
// Create new views (invoked by the layout manager)
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.row, parent, false);
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(v);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
// this callback will be constantly called during scrolling
// therefore, to make it smooth, we should not make any expensive operations here
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.title.setText(pojos.get(position).getTitle());
holder.desc.setText(pojos.get(position).getDesc());
holder.imageView.setImageResource(pojos.get(position).getImage());
// you'll need to implement this function based on the way you decide to save clicked state for each clicked view
if(isClickedState(position)) {
holder.imageView.setImageResource(R.drawable.heart_red);
} else {
// provide some default background
holder.imageView.setImageResource(R.drawable.default);
}
holder.imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// you'll need to implement this function to save clicked position
saveClickForPosition(position)
imageView.setImageResource(R.drawable.heart_red);
}
});
}
// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
return pojos.size();
}
}
这应该是您调试的起点,因为遵循此模式将保证正确的回收。
正如在另一个答案中也提到的那样,你需要记住每个项目的点击状态,并且在MyPojo对象或其他地方保持这种状态应该相对容易实现。
答案 3 :(得分:0)
我有一个类似的问题,(在多个列表元素上有一个数字更改而不是一个)。我假设它是因为循环视图的工作方式,我能够通过设置我计划改变为我想要的任何内容来修复它。
IE:如果你想将背景更改为蓝色,当你加载列表时,那些不应该是蓝色到灰色的(或任何你想要的默认值)。
所以这里:
ViewHolder vh = new ViewHolder(v);
return vh;
您想指定默认值
答案 4 :(得分:0)
如果您知道项目数并且它是固定的,则可以使用
setItemViewCacheSize( numItems)
这将解决该问题,因为它将在该数字之后开始重复使用项目,尽管您将失去recyclerview的所有好处。
答案 5 :(得分:-1)
这里尝试使用此适配器:
public class myAdapter extends RecyclerView.Adapter<CopyOfConversationAdapter.ViewHolder> {
private ArrayList<conversationItem> pojos;
// inner class to hold a reference to each item of RecyclerView
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView title;
TextView desc;
ImageView imageView;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
title= (TextView) itemLayoutView.findViewById(R.id.title);
desc= (TextView) itemLayoutView.findViewById(R.id.desc);
imageView= (ImageView) itemLayoutView.findViewById(R.id.imageView);
}
}
// Return the size of your itemsData (invoked by the layout manager)
@Override
public int getItemCount() {
return pojos.size();
}
public CopyOfConversationAdapter(Pojos[] pojos) {
this.pojos = new ArrayList<conversationItem>();
this.pojos.addAll(Arrays.asList(Items));
}
// Create new views (invoked by the layout manager)
@Override
public CopyOfConversationAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View itemLayoutView;
itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.comments_item_layout_, null);
ViewHolder viewHolder = new ViewHolder(itemLayoutView);
return viewHolder;
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
// - get data from your itemsData at this position
// - replace the contents of the view with that itemsData
viewHolder.title.setText(pojos.get(position).getSender());
viewHolder.desc.setText(pojos.get(position).getSnippet());
viewHolder.imageView.setText(pojos.get(position).getIcon());
viewHolder.imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
desc.setText("clicked");
desc.setBackgroundColor(Color.BLUE);
imageView.setImageResource(R.drawable.heart_red);
}
});
}
}