Naresh Sharma
Naresh Sharma

Reputation: 4323

Recyclerview with multiple layouts duplicate items on scrolling

In Recyclerview with multiple layouts I override the getItemViewType() method by which I decide which layout to display. Strange issue occurred when on scrolling duplicate items appeared and change their position too.

When I hardcode the things on the basis of the position then no duplicate's like below code sample.

@Override 
public int getItemViewType (int position) 
{ 
    switch (position) 
    {  
    case 0:
        return TYPE_HEADER; 

    case 8:
        return TYPE_HEADER;

    default:
        return TYPE_ITEMS; 
     }
}

But duplicate's start when I change it like below code and make it dynamic instead of static positions.

String tempDate = "";
List<String> items = new ArrayList<>();
items.add("2017-01-01");
items.add("2017-01-01");
items.add("2017-01-02");
items.add("2017-01-02");
items.add("2017-01-02");
items.add("2017-01-03");
items.add("2017-01-03");
items.add("2017-01-03");
items.add("2017-01-04");
@Override 
public int getItemViewType (int position) 
{ 
   if(!tempDate.equalsIgnoreCase(items.get(position)){
       tempDate = items.get(position);
       return  TYPE_HEADER;
}  else{
       tempDate = items.get(position);
       return TYPE_ITEMS;       
}


@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {

    switch (viewHolder.getItemViewType()) {
        case TYPE_HEADER:
            //Make your header view visible
            initialize the view resources of HeaderLayout xml 
            break;        

        case TYPE_ITEM:
            //Make your second header view visible
            initialize the view resources of ItemLayout xml
            break;
    }

}

The other methods onBindViewHolder(), onCreateViewHolder() are fine as per my knowledge. Any help is appreciated.

Upvotes: 1

Views: 1340

Answers (3)

Rahul Pareta
Rahul Pareta

Reputation: 796

You can use this code

@Override
public int getItemViewType(int position) {
    String tem = "";
    for (int i = 0; i < items.size(); i++) {
        if (!tem.equals(items.get(i))) {
            tem=items.get(i);
            if (i == position) {
                 return TYPE_HEADER;
            }
        } else {
            if (i == position) {
                return TYPE_items;
            }
        }
    }
    return -1;
}

Upvotes: 0

Doron Yakovlev Golani
Doron Yakovlev Golani

Reputation: 5470

I think simple is better here:

private List<String> items = new ArrayList<>();

@Override
public int getItemViewType (int position) {
    if (position == 0) {
        return TYPE_HEADER;
    }

    String textForPosition = items.get(position);
    String textForPrevPosition = items.get(position - 1);

    if (textForPosition.equalsIgnoreCase(textForPrevPosition)) {
        return TYPE_HEADER;
    }
    return TYPE_ITEM;
}


@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {

    // Use dateText instead of tempDate
    String dateText = items.get(i);
    switch (viewHolder.getItemViewType()) {
        case TYPE_HEADER:
            //Make your header view visible initialize the view resources of HeaderLayout xml
            break;

        case TYPE_ITEM:
            //Make your second header view visible initialize the view resources of ItemLayout xml
            break;
    }

}

Upvotes: 1

beeb
beeb

Reputation: 1615

I think the problem is in that code section:

if(!tempDate.equalsIgnoreCase(items.get(position)){
   tempDate = items.get(position);
   return  TYPE_HEADER;
}  
else{
   tempDate = items.get(position);
   return TYPE_ITEMS;   
}

I'd recomment to create another list in your adapter which called headers. I already implemented a class which extends a baseadapter which i am using for a navigation list with headers and items. Maybe you can take some ideas for your problem:

/**
 * Adapter class for the navigation list. It handles items and section header items.
 */
public class CDMNavListAdapter extends BaseAdapter {

  /**
   * Constructor
   *
   * @param p_Context the context
   */
  public CDMNavListAdapter(Context p_Context) {
    m_Inflater = (LayoutInflater) p_Context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  }

  /**
   * Adds an item to the list
   *
   * @param p_Item the item to add
   */
  public void addItem(CDMNavigationItem p_Item) {
    m_Data.add(p_Item);
    notifyDataSetChanged();
  }

  /**
   * Adds a section header item to the list
   *
   * @param p_Item the section head item
   */
  public void addSectionHeaderItem(String p_Item) {
    // CDMNavigationItem is just a wrapper: CDMNavigationItem(int p_iType , String p_Title, int p_iResIcon, String p_Count)
    m_Data.add(new CDMNavigationItem(ADMNavigationTypes.iSECTION_HEADER, p_Item, -1, "0"));
    m_SectionHeader.add(m_Data.size() - 1);
    notifyDataSetChanged();
  }

  @Override
  public int getItemViewType(int p_iPosition) {
    return m_SectionHeader.contains(p_iPosition) ? iTYPE_SEPARATOR : iTYPE_ITEM;
  }

  @Override
  public int getViewTypeCount() {
    return 2;
  }

  @Override
  public int getCount() {
    return m_Data.size();
  }

  @Override
  public CDMNavigationItem getItem(int p_iPosition) {
    return m_Data.get(p_iPosition);
  }

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

  @Override
  public View getView(int p_iPosition, View p_ConvertView, ViewGroup p_Parent) {
    int l_iRowType = getItemViewType(p_iPosition);

    // sets the text to the item / section head item
    CDMNavigationItem l_NavItem = m_Data.get(p_iPosition);
    switch(l_iRowType) {
      // item
      case iTYPE_ITEM:
        // item layout code
        break;
      // section header
      case iTYPE_SEPARATOR:
        // section header layout code
        break;
    }

    return p_ConvertView;
  }

  /**
   * Returns true if the item on the position is a section header item
   *
   * @param p_iPosition the position
   * @return true if the item on the position is a section header item
   */
  public boolean isSectionHeader(int p_iPosition) {
    return getItemViewType(p_iPosition) == iTYPE_SEPARATOR;
  }

  /**
   * Gets the position without header sections
   * @param p_iPosition the position
   * @return int the position without header sections
   */
  public int getPositionWithoutHeaderSections(int p_iPosition) {
    int l_iPositionWithoutHeaderSections = -1;

    for(int i = 0; i <= p_iPosition; i++) {
      if(!isSectionHeader(i))
        l_iPositionWithoutHeaderSections++;
    }

    return l_iPositionWithoutHeaderSections;
  }

  /**
   * Clears the data
   */
  public void clear() {
    m_Data.clear();
    m_SectionHeader.clear();

    notifyDataSetChanged();
  }

  private static final int iTYPE_ITEM = 0;
  private static final int iTYPE_SEPARATOR = 1;

  private List<CDMNavigationItem> m_Data = new ArrayList<>();
  private Set<Integer> m_SectionHeader = new TreeSet<>();

  private LayoutInflater m_Inflater;
} 

Upvotes: 0

Related Questions