RecyclerView在滚动时弄乱了数据

时间:2015-05-06 16:06:35

标签: java android android-recyclerview

滚动向下和向上滚动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;
}
}

10 个答案:

答案 0 :(得分:36)

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

holder.setIsRecyclable(false);

您的回收商将不再回收,因此当您滚动时项目将是相同的,如果您想要删除某些项目,请不要使用notifyitemRemoved(position),而是使用notifyDataSetChanged()

答案 1 :(得分:12)

在适配器构造函数中添加setHasStableIds(true); 在适配器中覆盖这两个方法。

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

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

答案 2 :(得分:2)

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);

}

答案 3 :(得分: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);
            }
        }
    });
}

答案 4 :(得分: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;
}

答案 5 :(得分: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 Adapter的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;
}

答案 6 :(得分:0)

尝试将其添加到适配器中。

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

答案 7 :(得分:0)

@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);
        }
    });
}

答案 8 :(得分: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)
       }         
    }
}

但是我认为这段代码很沉重,因为您将其用于大型数据列表。

答案 9 :(得分:0)

如果有人可能会遇到视点持有人中某些字段获取随机值的问题,请尝试将所有字段设置为至少具有默认值。