RecyclerView 中的 onClick 按钮适用于多个视图而不是自身
onClick button inside RecyclerView works for multiple view instead of itself
我正在编写一个翻译应用程序 words.There 大约 40 个单词合而为一 RecyclerView
。每个单词都有一个按钮显示该单词的含义。
我为 onBindViewHolder
内的那个按钮写了 onClickListener
,如下所示:
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
final int pos = position;
holder.tv_wordText.setText(words.get(pos).getWord());
holder.tv_meaningText.setText(words.get(pos).getMeaning());
holder.btn_showAnswer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
holder.tv_meaningText.setVisibility(View.VISIBLE);
holder.btn_showAnswer.setVisibility(View.INVISIBLE);
}
});
}
但是当我点击那个按钮时,它不仅会显示自己的意思,还会每隔 5 个单词显示下一个。例如,如果我点击第一个单词,它会显示 1,6,11,16,21
等等。第二个按钮也显示 2,7,12,17,22
。应用程序的所有其他部分都可以正常工作,但那个按钮不能正常工作,我不知道为什么?我也在 ViewHolder
class 里面做了,但是效果一样。有没有正确的方法?
3 天后,我发现了一个适合我的棘手代码。
我意识到每次滚动 RecyclerView
时,onBindViewHolder
运行 中的每个可见 RecyclerView
中的 ViewHolder
代码。所以我决定在 onBindViewHolder
中放入隐藏该元素的代码:
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
final int pos = position;
holder.tv_wordText.setText(words.get(pos).getWord());
holder.tv_meaningText.setText(words.get(pos).getMeaning());
holder.tv_meaningText_cv.setVisibility(View.INVISIBLE);
holder.btn_showAnswer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
holder.tv_meaningText_cv.setVisibility(View.VISIBLE);
}
});
}
但它也使所有其他元素不可见。
如果您有更好的解决方案,请在这里提出。
这与 RecyclerView
的 回收 行为有关。当您将视图滚动到屏幕的一个边缘之外时,系统最终将 re-use 该视图用于您的单词列表中的另一个位置。由于您只是有条件地设置某些视图的可见性,因此最后设置的任何内容都将保留在 re-used 视图中。因此,如果您单击以显示一个词的含义,下一次该视图是 re-used,您将能够看到新词的含义。
对于 RecyclerView
,最好始终让您的数据模型(您的 words
列表)能够完全代表您的状态。我不知道 words
中的每个元素到底是什么样子,但我可以看到每个元素都有一个 getWord()
和一个 getMeaning()
函数。我认为您也应该为此添加一个 isMeaningVisible(): Boolean
函数。然后你可以有这样的东西:
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Word word = words.get(position);
holder.tv_wordText.setText(word.getWord());
holder.tv_meaningText.setText(word.getMeaning());
holder.tv_meaningText_cv.setVisibility(word.isMeaningVisible() ? View.VISIBLE : View.INVISIBLE);
}
另一个问题是如何处理按钮上的点击。我注意到在您的代码中有 final int pos
;这不是一个好主意。 RecyclerView
允许您插入或删除单个元素,因此传递给 onBindViewHolder()
的位置可以随时间变化。因此,最好在 onCreateViewHolder()
中设置点击侦听器。
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ViewHolder holder = new ViewHolder(LayoutInflater.from(context).inflate(R.layout.word_list_adapter, parent, false));
holder.btn_showAnswer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position = holder.getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
Word word = words.get(position);
word.setMeaningVisible(!word.isMeaningVisible());
notifyItemChanged(position);
}
}
});
return holder;
}
我正在编写一个翻译应用程序 words.There 大约 40 个单词合而为一 RecyclerView
。每个单词都有一个按钮显示该单词的含义。
我为 onBindViewHolder
内的那个按钮写了 onClickListener
,如下所示:
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
final int pos = position;
holder.tv_wordText.setText(words.get(pos).getWord());
holder.tv_meaningText.setText(words.get(pos).getMeaning());
holder.btn_showAnswer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
holder.tv_meaningText.setVisibility(View.VISIBLE);
holder.btn_showAnswer.setVisibility(View.INVISIBLE);
}
});
}
但是当我点击那个按钮时,它不仅会显示自己的意思,还会每隔 5 个单词显示下一个。例如,如果我点击第一个单词,它会显示 1,6,11,16,21
等等。第二个按钮也显示 2,7,12,17,22
。应用程序的所有其他部分都可以正常工作,但那个按钮不能正常工作,我不知道为什么?我也在 ViewHolder
class 里面做了,但是效果一样。有没有正确的方法?
3 天后,我发现了一个适合我的棘手代码。
我意识到每次滚动 RecyclerView
时,onBindViewHolder
运行 中的每个可见 RecyclerView
中的 ViewHolder
代码。所以我决定在 onBindViewHolder
中放入隐藏该元素的代码:
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
final int pos = position;
holder.tv_wordText.setText(words.get(pos).getWord());
holder.tv_meaningText.setText(words.get(pos).getMeaning());
holder.tv_meaningText_cv.setVisibility(View.INVISIBLE);
holder.btn_showAnswer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
holder.tv_meaningText_cv.setVisibility(View.VISIBLE);
}
});
}
但它也使所有其他元素不可见。
如果您有更好的解决方案,请在这里提出。
这与 RecyclerView
的 回收 行为有关。当您将视图滚动到屏幕的一个边缘之外时,系统最终将 re-use 该视图用于您的单词列表中的另一个位置。由于您只是有条件地设置某些视图的可见性,因此最后设置的任何内容都将保留在 re-used 视图中。因此,如果您单击以显示一个词的含义,下一次该视图是 re-used,您将能够看到新词的含义。
对于 RecyclerView
,最好始终让您的数据模型(您的 words
列表)能够完全代表您的状态。我不知道 words
中的每个元素到底是什么样子,但我可以看到每个元素都有一个 getWord()
和一个 getMeaning()
函数。我认为您也应该为此添加一个 isMeaningVisible(): Boolean
函数。然后你可以有这样的东西:
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Word word = words.get(position);
holder.tv_wordText.setText(word.getWord());
holder.tv_meaningText.setText(word.getMeaning());
holder.tv_meaningText_cv.setVisibility(word.isMeaningVisible() ? View.VISIBLE : View.INVISIBLE);
}
另一个问题是如何处理按钮上的点击。我注意到在您的代码中有 final int pos
;这不是一个好主意。 RecyclerView
允许您插入或删除单个元素,因此传递给 onBindViewHolder()
的位置可以随时间变化。因此,最好在 onCreateViewHolder()
中设置点击侦听器。
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ViewHolder holder = new ViewHolder(LayoutInflater.from(context).inflate(R.layout.word_list_adapter, parent, false));
holder.btn_showAnswer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position = holder.getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
Word word = words.get(position);
word.setMeaningVisible(!word.isMeaningVisible());
notifyItemChanged(position);
}
}
});
return holder;
}