2015-05-06 3 views
5

Ein Problem beim Scrollen RecyclerView nach dem Scrollen nach unten und oben. Die Idee ist, die Farbe der Elemente zu ändern, aber wenn ich nach unten scrolle, ist alles großartig und wenn die Schriftrolle nach oben geht - ändern sich die Elemente, die nicht farbig sein sollen.RecyclerView vermasselt Daten beim Scrollen

Hier ist mein Adapter:

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

Antwort

2

Es gibt ein Problem in Ihrem onBindViewHolder(...), sein sollte:

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

} 
+0

Das funktionierte für mich. Ich habe gedacht, dass Default-Werte per defauf festgelegt sind, war aber völlig missverständlich. – MeLine

26

ich das gleiche Problem und die einzige Lösung, die ich für diese gefunden hatte, ist:

holder.setIsRecyclable(false); 

Ihr Recycler wird nicht mehr recycelt, so dass die Elemente beim Scrollen identisch sind. und wenn Sie ein Element löschen möchten, verwenden Sie nicht notifyitemRemoved(position), sondern stattdessen notifyDataSetChanged().

+2

Oben ist hilfreich für mich danke ..... – Dilip

+5

ACHTUNG: Sie sollten keinen dieser Ratschläge verwenden. Wie Jhonatan selbst sagte, werden die Ansichten nicht mehr recycelt, was den Zweck des Recycler-View komplett verwirkt und zu schlechter Performance führen wird. Auch die Brute-Force-Methode notifyDataSetChanged() sollte immer der letzte Ausweg sein - wenn möglich, versuchen Sie, dem Adapter genau mitzuteilen, welche Elemente beim Entfernen oder Hinzufügen von Daten aktualisiert wurden - dies verbessert nicht nur die Leistung, sondern lässt es auch Animationen entsprechend ausführen – jhm

+0

Danke Mann ich wurde diese Ausgabe letzten 3 Tag gefunden .. –

0

onBindHolder mehrmals aufgerufen als Recycler View benötigt eine Ansicht, es sei denn, neue. Jedes Mal, wenn Sie visilibity in untergeordneten Ansichten festlegen, ändern sich auch die Zustände anderer Ansichten.

Wenn Sie nach oben oder unten scrollen, werden diese Ansichten mit falschen Sichtbarkeitsoptionen neu gezeichnet. Geben Sie daher immer beide Bedingungen an, da die Recycler-Ansicht den vorherigen Zustand/die früheren Bedingungen/Werte unserer Widgets nicht kennt.

Lösung:

Wenn in Block Wenn Sie die Sichtbarkeit von jedem Android widget.setVisibility (View.Gone), dann in anderen Block legen Sie es entgegengesetzte Wert Sichtbarkeit wie widget.setVisibility (View.Visible) ist gesetzt haben überwinde das obige 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); 
      } 
     } 
    }); 
} 
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; 
} 
8

setHasStableIds(true); in Ihrem Adapter Konstruktor hinzufügen und diese beiden methodes in Adapter außer Kraft setzen .

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

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

Das hat bei mir funktioniert. Kannst du mehr erklären, warum das funktioniert? –

+0

Kannst du dazu mehr erklären? – Rino