问题
I'm using RecyclerView to display a list of marks, and each mark of the value is shown as a CardView. But some contents of the cards are lost after the scrolling the RecyclerView down and scrolling back, as shown in the two screenshots below. The contents in the red rectangle is lost after scrolling.
BEFORE THE SCROLLING;
AFTER THE SCROLLING;
I'm wondering whether or not it's a bug of RecyclerView and find no solution after Googling for it.
All views are invisible except the title, their visibilities are depends on the mark's value.
Does anyone know why this would happen?
回答1:
onBindHolder called several times as recycler needs a view unless new one in case of view type changed. So each time you set visilibity in child views, other views states are also changes.
Whenever you scroll up and down, these views are getting re-drawed with wrong visibility options.
Solution :
You have a setValue method check values and set to view. If neccessary it calls another method "showView". You need to implement else statement (which is value is 0 or null) and hideView there...
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);
}
回答2:
After battling with this same issue for about 24 hours, I found a solution that worked for me. The key was using the setIsRecyclable()
method of RecyclerView.ViewHolder
class.
Here is a section of my onBindViewHolder()
code.
@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);
}
});
}
回答3:
onBindHolder called several times as Recycler View needs a view unless new one. So each time you set visilibity in child views, other views states are also changes.
Whenever you scroll up and down, these views are getting re-drawed with wrong visibility options so always specify both the conditions cause recycler view doesn't know the previous state/conditions/values of our widgets.
Solution :
If in If block you set visibility of any android widget.setVisibility(View.Gone) then in else block you have to set it's visibility opposite vwith widget.setVisibility(View.Visible) to overcome the above problem.
@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);
}
}
});
}
回答4:
This is due to the views being reused when scrolling occurs. To fix this you will need to reset any views that have been made visible for other cells (YUZME in your example).
Inside setValue(Object value, TextView textView, TableRow row, View seperator) simply make all txtVize* hidden again.
Recycler view starts off with 3 views:
[0] FIZ104
[1] MAT102
[2] REK361
When the view is scrolled to the bottom views [0] and [1] are recycled. When you scroll back to the top view [2] is used to display the data contained in FIZ104 and MAT102 and any changes made for REK361 are still there.
回答5:
If you are facing problems with the the visibility issue for ex. if u have set the visibility of the view based on condition , but if you scroll down, the views get refreshed and the visibility of the view inside that recycler view item gets changes and hence violating the condition.
Here's a solution:
1. First assign tag to that view whose visibility you want to maintain.
holder.myImageView.setTag(myTeamLists.get(position));
MyDTOClass checkWetherToShow=(MyDTOClass)holder.myImageView.getTag();
2. Now apply your condition and toggle the visibility
if (checkWetherToShow.getHasToShowImage()){
holder.myImageView.setVisibility(View.VISIBLE);
}else{
holder.myImageView.setVisibility(View.GONE);
}
The key to the answer here is don't forget the else part.
来源:https://stackoverflow.com/questions/29702357/android-recyclerview-content-messed-up-after-scrolling