RecyclerView 滚动时弄乱了数据

问题描述 投票:0回答:12

上下滚动后滚动 RecyclerView 时出现问题。这个想法是改变元素的颜色,但是当我向下滚动时一切都很好,当滚动向上时 - 不应该着色的元素正在改变颜色。

这是我的适配器:

public class NotificationsAdapter extends RecyclerView.Adapter<NotificationsAdapter.ViewHolder> {

private NotificationData notificationData;
private Context mContext;
private ArrayList<NotificationData> infromationList = new ArrayList<>();


public NotificationsAdapter(Context context, ArrayList<NotificationData> infromationList) {
    this.infromationList = infromationList;
    this.mContext = context;
}


@Override
public NotificationsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View itemLayoutView;
    ViewHolder viewHolder;

    itemLayoutView = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.notification_single_item, parent, false);
    viewHolder = new ViewHolder(itemLayoutView, viewType);

    return viewHolder;
}

@Override
public void onBindViewHolder(NotificationsAdapter.ViewHolder holder, int position) {

    notificationData = infromationList.get(position);
    holder.notificationDate.setText(convertDate(notificationData.getDate()));
    holder.notificationStatus.setText(notificationData.getNotificationStatus());
    holder.orderDescription.setText(notificationData.getNotificationLabel());

    if ("true".equals(notificationData.getReadStatus())) {
        holder.root.setBackgroundColor(mContext.getResources().getColor(R.color.white));
        holder.notificationStatus.setTypeface(Typeface.create("sans-serif-light", Typeface.NORMAL));
    }

}

@Override
public int getItemCount() {
    return (null != infromationList ? infromationList.size() : 0);
}

public static class ViewHolder extends RecyclerView.ViewHolder {

    public TextView notificationDate;
    public TextView notificationStatus;
    public TextView orderDescription;
    public LinearLayout root;

    public ViewHolder(View itemView, int position) {
        super(itemView);

        notificationDate = (TextView) itemView.findViewById(R.id.notificationDate);
        notificationStatus = (TextView) itemView.findViewById(R.id.notificationStatus);
        orderDescription = (TextView) itemView.findViewById(R.id.orderDescription);
        root = (LinearLayout) itemView.findViewById(R.id.root);
    }

}

private String convertDate(String date) {
    String convertedDate;

    String[] parts = new String[2];
    parts = date.split("T");
    date = parts[0];

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd");
    Date testDate = null;
    try {
        testDate = sdf.parse(date);
    }catch(Exception ex){
        ex.printStackTrace();
    }
    SimpleDateFormat formatter = new SimpleDateFormat("dd.mm.yyyy");
    convertedDate = formatter.format(testDate);

    return convertedDate;
}
}
java android android-recyclerview
12个回答
49
投票

我有同样的问题,我找到的唯一解决方案是:

holder.setIsRecyclable(false);

您的回收商将不再回收,因此滚动时项目将相同,如果您想删除某些项目,请不要使用

notifyitemRemoved(position)
,请改用
notifyDataSetChanged()


40
投票

在您的适配器构造函数中添加

setHasStableIds(true);
和 在适配器中覆盖这两个方法。

@Override
public long getItemId(int position) {
            return position;
}

@Override
public int getItemViewType(int position) {
       return position;
}

6
投票

你的

onBindViewHolder(...)
有问题,应该是:

if ("true".equals(notificationData.getReadStatus())) {
    holder.root.setBackgroundColor(mContext.getResources().getColor(R.color.white));
    holder.notificationStatus.setTypeface(Typeface.create("sans-serif-light", Typeface.NORMAL));
}
else {
    holder.root.setBackgroundColor(yourDefaultColor);
    holder.notificationStatus.setTypeface(yourDefaultTypeface);

}

4
投票
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
    final UserData userdata = userdataList.get(position);

    holder.setIsRecyclable(false);

    holder.name.setText(userdata.getName());
    holder.active.setChecked(userdata.getActive());

    String userPic = userdata.getPic();


    holder.active.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked){
            userdata.setActive(isChecked);
        }
    });
}

1
投票

onBindHolder 多次调用,因为 Recycler View 需要一个视图,除非是新视图。因此,每次您在子视图中设置可见性时,其他视图状态也会发生变化。

无论何时上下滚动,这些视图都会使用错误的可见性选项重新绘制,因此请始终指定这两个条件,因为回收器视图不知道我们的小部件之前的状态/条件/值。

解决方案:

如果在 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);
            }
        }
    });
}

1
投票

尝试在适配器中添加它。

@Override
public int getItemViewType(int position)
{
    return position;
}

1
投票

如果有人可能会遇到取景器中的某些字段获取随机值的问题,请尝试使用至少任何默认值设置所有字段。


0
投票
 @Override
public DataObjectHolder onCreateViewHolder(ViewGroup parent,
                                           int viewType) {
    View view = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.custom_layout, parent, false);

    DataObjectHolder dataObjectHolder = new DataObjectHolder(view);
    dataObjectHolder.setIsRecyclable(false);

    return dataObjectHolder;
}

0
投票

最好的方法是将 ArrayList 指定为模型,并具有一些参数并为此定义 setter 和 getter。

package com.test.mohammaddvi.snappfood.Model;

public class OfferList {
private boolean visibilityOrder;
private int number;

public OfferList(int number, boolean visibilityOrder) {
   this.number=number;
   this.visibilityOrder=visibilityOrder;
}

public boolean isVisibilityOrder() {
    return visibilityOrder;
}

public void setVisibilityOrder(boolean visibilityOrder) {
    this.visibilityOrder = visibilityOrder;
}

public int getNumber() {
    return number;
}

public void setNumber(int number) {
    this.number = number;
}

}

并将变量设置为您想要的位置,为了获取,您必须在 recyclerview 适配器的 onBindViewHolder 中执行此操作:

if (offerList.isVisibilityOrder()) {
        holder.foodMinusButton.setVisibility(View.VISIBLE);
        holder.foodOrderNumber.setText(offerList.getNumber() + "");
        holder.foodOrderNumber.setVisibility(View.VISIBLE);
    } else {
        holder.foodMinusButton.setVisibility(View.INVISIBLE);
    }

并指出它是您的 recyclerview 适配器:

public class RecyclerViewMenuFragmentAdapter extends RecyclerView.Adapter<RecyclerViewMenuFragmentAdapter.SingleItemInMenuFragment> {

private ArrayList<Food> foodList;
private Context mContext;
private List<OfferList> offers;

public RecyclerViewMenuFragmentAdapter(ArrayList<Food> foodList, Context mContext, List<OfferList> offers) {
    this.foodList = foodList;
    this.mContext = mContext;
    this.offers = offers;
}

0
投票
class AnyRVAdapter: androidx.recyclerview.widget.RecyclerView.Adapter<AnyRVAdapter.MViewHolder>() {

// put saver outside viewholder
val saveLayId = mutableListOf<Int>()

inner class MViewHolder(itemView: View) :
    androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) {       

    fun bindModel(d: TesListModel.MList, position:Int) {

       // concept here
       val showedId= saveLayId.find { s -> s == layoutPosition}
       if (idClicked == null) {            
           // save the layout id
           lyClicked.visibility = View.VISIBLE
           saveLayId.add(layoutPosition)
       } else {
           // remove the layout id
           lyClicked.visibility = View.INVISIBLE
           saveLayId.remove(layoutPosition)
       }         
    }
}

但我认为如果您用于大型数据集,这段代码会很重。


0
投票

伙计们,这对我有用..

override fun setHasStableIds(hasStableIds: Boolean) {
    setHasStableIds(true)
}

override fun getItemId(position: Int): Long {
    return position.toLong()
}

override fun getItemViewType(position: Int): Int {
    return position
}

0
投票

在您的 onBindView 方法中,请将此设置为 false

holder.setIsRecyclable(假)

© www.soinside.com 2019 - 2024. All rights reserved.