Android:滚动后 RecyclerView 内容混乱
Android: RecyclerView content messed up after scrolling
我正在使用 RecyclerView 显示标记列表,值的每个标记显示为 CardView。但是在向下滚动 RecyclerView 并向后滚动后,卡片的一些内容丢失了,如下面的两个屏幕截图所示。滚动后红色矩形框内容丢失
滚动之前;
滚动之后;
我在想是不是RecyclerView的bug,Google了一下也没有解决
除标题外,所有视图都是不可见的,它们的可见性取决于标记的值。
有谁知道为什么会这样?
这是因为发生滚动时视图被重用。要解决此问题,您需要重置所有已对其他单元格可见的视图(在您的示例中为 YUZME)。
在 setValue(Object value, TextView textView, TableRow row, View seperator) 中简单地再次隐藏所有 txtVize*。
Recycler 视图从 3 个视图开始:
[0] FIZ104
[1] MAT102
[2] REK361
当视图滚动到底部时视图 [0] 和 [1] 被回收。当您滚动回顶部视图时,[2] 用于显示 FIZ104 和 MAT102 中包含的数据,并且对 REK361 所做的任何更改仍然存在。
onBindHolder() 被调用多次,因为回收器需要一个视图,除非在更改视图类型时有一个新视图。
因此,每次您在子视图中设置可见性时,其他视图状态也会发生变化。
每当您向上和向下滚动时,这些视图都会使用错误的可见性选项重新绘制。
解法:
您有一个 setValue 方法检查值并设置为查看。如果需要,它会调用另一种方法“showView”。您需要实现 else 语句(值为 0 或 null)并在那里隐藏视图...
void setValue(Object value, TextView textView, TableRow row, View seperator) {
if (value != null) {
if (!isEmpty(value.toString())) {
textView.setText(String.valueOf(value));
showViews(row, seperator);
}
} else
hideViews(row, seperator);
}
private void showViews(TableRow row, View seperator) {
row.setVisibility(View.VISIBLE);
seperator.setVisibility(View.VISIBLE);
}
private void hideViews(TableRow row, View seperator) {
row.setVisibility(View.INVISIBLE); // if there is a empty space change it with View.GONE
seperator.setVisibility(View.INVISIBLE);
}
onBindHolder 调用了几次,因为 Recycler View 需要一个视图,除非是新视图。所以每次在子视图中设置可见性时,其他视图状态也会发生变化。
每当您向上和向下滚动时,这些视图都会使用错误的可见性选项重新绘制,因此请始终指定这两个条件,因为回收器视图不知道之前的 state/conditions/values 我们的小部件。
解决方案:
如果在 If 块中您设置了任何 android widget.setVisibility(View.Gone) 的可见性,那么在 else 块中您必须将它的可见性设置为与 widget.setVisibility(View.Visible) 克服上述问题。
@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
viewHolder.tvName.setText(ModelCategoryProducts.name.get(i));
viewHolder.tvPrice.setText("Rs."+String.format("%.2f", Float.parseFloat(ModelCategoryProducts.price.get(i))));
if(ModelCategoryProducts.special_price.get(i).equals("null")) {
viewHolder.tvSpecialPrice.setVisibility(View.GONE); // here visibility is gone and in else it's opposite visibility i set.
viewHolder.tvPrice.setTextColor(Color.parseColor("#ff0000"));
viewHolder.tvPrice.setPaintFlags(0);// here paint flag is 0 and in else it's opposite flag that i want is set.
}else if(!ModelCategoryProducts.special_price.get(i).equals("null")){
viewHolder.tvPrice.setTextColor(Color.parseColor("#E0E0E0"));
viewHolder.tvSpecialPrice.setVisibility(View.VISIBLE);
viewHolder.tvSpecialPrice.setText("Rs." + String.format("%.2f", Float.parseFloat(ModelCategoryProducts.special_price.get(i))));
viewHolder.tvPrice.setPaintFlags(viewHolder.tvPrice.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
if (!ModelCategoryProducts.image_url.get(i).isEmpty()) {
Picasso.with(context)
.load(ModelCategoryProducts.image_url.get(i))
.into(viewHolder.ivProduct);
}
viewHolder.setClickListener(new ItemClickListener() {
@Override
public void onClick(View view, int position, boolean isLongClick) {
if (isLongClick) {
// Toast.makeText(context, "#" + position + " - " + ModelCategoryProducts.name.get(position) + " (Long click)", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "#" + position + " - " + ModelCategoryProducts.name.get(position), Toast.LENGTH_SHORT).show();
Intent i = new Intent(context, ProductDetail.class);
i.putExtra("position",position);
i.putExtra("flagHlvCheck", 5);
context.startActivity(i);
}
}
});
}
在与同一问题斗争了大约 24 小时后,我找到了适合我的解决方案。关键是使用 RecyclerView.ViewHolder
class 的 setIsRecyclable()
方法。
这是我的 onBindViewHolder()
代码的一部分。
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
final DataSource dataSource = dataSourceList.get(position);
holder.setIsRecyclable(false);
holder.name.setText(dataSource.getName());
holder.active.setChecked(dataSource.getActive());
String logoStr = dataSource.getLogo();
//Logo
/**
* Do all the logo insertion stunts here
*/
/**
* Register the changes to the Switch
*/
holder.active.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked){
dataSource.setActive(isChecked);
}
});
}
如果您遇到 ex 的可见性问题。如果您已根据条件设置视图的可见性,但如果您向下滚动,则视图会刷新,并且该回收器视图项内的视图的可见性会发生变化,从而违反条件。
解决方法如下:
1.首先将 tag 分配给您要保持其可见性的视图。
holder.myImageView.setTag(myTeamLists.get(position));
MyDTOClass checkWetherToShow=(MyDTOClass)holder.myImageView.getTag();
2。现在应用您的条件并切换可见性
if (checkWetherToShow.getHasToShowImage()){
holder.myImageView.setVisibility(View.VISIBLE);
}else{
holder.myImageView.setVisibility(View.GONE);
}
这里答案的关键是不要忘记其他部分。
我正在使用 RecyclerView 显示标记列表,值的每个标记显示为 CardView。但是在向下滚动 RecyclerView 并向后滚动后,卡片的一些内容丢失了,如下面的两个屏幕截图所示。滚动后红色矩形框内容丢失
滚动之前;
滚动之后;
我在想是不是RecyclerView的bug,Google了一下也没有解决
除标题外,所有视图都是不可见的,它们的可见性取决于标记的值。
有谁知道为什么会这样?
这是因为发生滚动时视图被重用。要解决此问题,您需要重置所有已对其他单元格可见的视图(在您的示例中为 YUZME)。
在 setValue(Object value, TextView textView, TableRow row, View seperator) 中简单地再次隐藏所有 txtVize*。
Recycler 视图从 3 个视图开始:
[0] FIZ104
[1] MAT102
[2] REK361
当视图滚动到底部时视图 [0] 和 [1] 被回收。当您滚动回顶部视图时,[2] 用于显示 FIZ104 和 MAT102 中包含的数据,并且对 REK361 所做的任何更改仍然存在。
onBindHolder() 被调用多次,因为回收器需要一个视图,除非在更改视图类型时有一个新视图。 因此,每次您在子视图中设置可见性时,其他视图状态也会发生变化。
每当您向上和向下滚动时,这些视图都会使用错误的可见性选项重新绘制。
解法:
您有一个 setValue 方法检查值并设置为查看。如果需要,它会调用另一种方法“showView”。您需要实现 else 语句(值为 0 或 null)并在那里隐藏视图...
void setValue(Object value, TextView textView, TableRow row, View seperator) {
if (value != null) {
if (!isEmpty(value.toString())) {
textView.setText(String.valueOf(value));
showViews(row, seperator);
}
} else
hideViews(row, seperator);
}
private void showViews(TableRow row, View seperator) {
row.setVisibility(View.VISIBLE);
seperator.setVisibility(View.VISIBLE);
}
private void hideViews(TableRow row, View seperator) {
row.setVisibility(View.INVISIBLE); // if there is a empty space change it with View.GONE
seperator.setVisibility(View.INVISIBLE);
}
onBindHolder 调用了几次,因为 Recycler View 需要一个视图,除非是新视图。所以每次在子视图中设置可见性时,其他视图状态也会发生变化。
每当您向上和向下滚动时,这些视图都会使用错误的可见性选项重新绘制,因此请始终指定这两个条件,因为回收器视图不知道之前的 state/conditions/values 我们的小部件。
解决方案:
如果在 If 块中您设置了任何 android widget.setVisibility(View.Gone) 的可见性,那么在 else 块中您必须将它的可见性设置为与 widget.setVisibility(View.Visible) 克服上述问题。
@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
viewHolder.tvName.setText(ModelCategoryProducts.name.get(i));
viewHolder.tvPrice.setText("Rs."+String.format("%.2f", Float.parseFloat(ModelCategoryProducts.price.get(i))));
if(ModelCategoryProducts.special_price.get(i).equals("null")) {
viewHolder.tvSpecialPrice.setVisibility(View.GONE); // here visibility is gone and in else it's opposite visibility i set.
viewHolder.tvPrice.setTextColor(Color.parseColor("#ff0000"));
viewHolder.tvPrice.setPaintFlags(0);// here paint flag is 0 and in else it's opposite flag that i want is set.
}else if(!ModelCategoryProducts.special_price.get(i).equals("null")){
viewHolder.tvPrice.setTextColor(Color.parseColor("#E0E0E0"));
viewHolder.tvSpecialPrice.setVisibility(View.VISIBLE);
viewHolder.tvSpecialPrice.setText("Rs." + String.format("%.2f", Float.parseFloat(ModelCategoryProducts.special_price.get(i))));
viewHolder.tvPrice.setPaintFlags(viewHolder.tvPrice.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
if (!ModelCategoryProducts.image_url.get(i).isEmpty()) {
Picasso.with(context)
.load(ModelCategoryProducts.image_url.get(i))
.into(viewHolder.ivProduct);
}
viewHolder.setClickListener(new ItemClickListener() {
@Override
public void onClick(View view, int position, boolean isLongClick) {
if (isLongClick) {
// Toast.makeText(context, "#" + position + " - " + ModelCategoryProducts.name.get(position) + " (Long click)", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "#" + position + " - " + ModelCategoryProducts.name.get(position), Toast.LENGTH_SHORT).show();
Intent i = new Intent(context, ProductDetail.class);
i.putExtra("position",position);
i.putExtra("flagHlvCheck", 5);
context.startActivity(i);
}
}
});
}
在与同一问题斗争了大约 24 小时后,我找到了适合我的解决方案。关键是使用 RecyclerView.ViewHolder
class 的 setIsRecyclable()
方法。
这是我的 onBindViewHolder()
代码的一部分。
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
final DataSource dataSource = dataSourceList.get(position);
holder.setIsRecyclable(false);
holder.name.setText(dataSource.getName());
holder.active.setChecked(dataSource.getActive());
String logoStr = dataSource.getLogo();
//Logo
/**
* Do all the logo insertion stunts here
*/
/**
* Register the changes to the Switch
*/
holder.active.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked){
dataSource.setActive(isChecked);
}
});
}
如果您遇到 ex 的可见性问题。如果您已根据条件设置视图的可见性,但如果您向下滚动,则视图会刷新,并且该回收器视图项内的视图的可见性会发生变化,从而违反条件。
解决方法如下:
1.首先将 tag 分配给您要保持其可见性的视图。
holder.myImageView.setTag(myTeamLists.get(position));
MyDTOClass checkWetherToShow=(MyDTOClass)holder.myImageView.getTag();
2。现在应用您的条件并切换可见性
if (checkWetherToShow.getHasToShowImage()){
holder.myImageView.setVisibility(View.VISIBLE);
}else{
holder.myImageView.setVisibility(View.GONE);
}
这里答案的关键是不要忘记其他部分。