1

Recycler view contains two textfields in each row. When we click on one textview it expands an expandable layout.This expandable layout duplicates on scrolling.

Here is my adaptor class

public class AlbumsAdapter extends RecyclerView.Adapter<AlbumsAdapter.MyViewHolder> {

private Context mContext;
private List<Album> albumList;

RecyclerView rv;
public class MyViewHolder extends RecyclerView.ViewHolder {
    public TextView title, count;
    public ImageView thumbnail, overflow;
    ExpandableRelativeLayout expandableLayout11;


    public MyViewHolder(final View view) {
        super(view);
        title = (TextView) view.findViewById(R.id.title);
        count = (TextView) view.findViewById(R.id.count);
        thumbnail = (ImageView) view.findViewById(R.id.thumbnail);
        expandableLayout11 = (ExpandableRelativeLayout)view. findViewById(R.id.expandableLayout11);


    }
}



public AlbumsAdapter(Context mContext, List<Album> albumList ) {
    this.mContext = mContext;
    this.albumList = albumList;

}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.album_card, parent, false);

    return new MyViewHolder(itemView);
}

@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
    final Album album = albumList.get(position);
    holder.title.setText(album.getName());
    holder.count.setText(album.getNumOfSongs() + " songs");

holder.title.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
          holder.expandableLayout11.toggle();

    }

});


   }

@Override
public int getItemCount() {
    return albumList.size();
}

}

My main activity is

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    getSupportActionBar().setHomeButtonEnabled(true);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    initCollapsingToolbar();

    recyclerView = (RecyclerView) findViewById(R.id.recycler_view);

    albumList = new ArrayList<>();
    adapter = new AlbumsAdapter(this, albumList );

    RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this);
    recyclerView.setLayoutManager(mLayoutManager);
    recyclerView.addItemDecoration(new GridSpacingItemDecoration(1, dpToPx(10), true));
    recyclerView.setItemAnimator(new DefaultItemAnimator());
    recyclerView.setAdapter(adapter);

    prepareAlbums();

    try {
        Glide.with(this).load(R.drawable.cover).into((ImageView) findViewById(R.id.backdrop));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

/**
 * Initializing collapsing toolbar
 * Will show and hide the toolbar title on scroll
 */
private void initCollapsingToolbar() {
    final CollapsingToolbarLayout collapsingToolbar =
            (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
    collapsingToolbar.setTitle("Developer List");
    AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appbar);
    appBarLayout.setExpanded(true);

    // hiding & showing the title when toolbar expanded & collapsed
    appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
        boolean isShow = false;
        int scrollRange = -1;

        @Override
        public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
            if (scrollRange == -1) {
                scrollRange = appBarLayout.getTotalScrollRange();
            }
            if (scrollRange + verticalOffset == 0) {
                collapsingToolbar.setTitle("Developer List");
                isShow = true;
            } else if (isShow) {
                collapsingToolbar.setTitle("Developer List");
                isShow = false;
            }
        }
    });
}


private void prepareAlbums() {
    int[] covers = new int[]{
            R.drawable.album1,
            R.drawable.album2,
            R.drawable.album3,
            R.drawable.album4,
            R.drawable.album5,
            R.drawable.album6,
            R.drawable.album7,
            R.drawable.album8,
            R.drawable.album9,
            R.drawable.album10,
            R.drawable.album11};

    Album a = new Album("True Romance", 13, covers[0]);
    albumList.add(a);

    a = new Album("Xscpae", 8, covers[1]);
    albumList.add(a);

    a = new Album("Maroon 5", 11, covers[2]);
    albumList.add(a);

    a = new Album("Born to Die", 12, covers[3]);
    albumList.add(a);

    a = new Album("Honeymoon", 14, covers[4]);
    albumList.add(a);

    a = new Album("I Need a Doctor", 1, covers[5]);
    albumList.add(a);

    a = new Album("Loud", 11, covers[6]);
    albumList.add(a);

    a = new Album("Legend", 14, covers[7]);
    albumList.add(a);

    a = new Album("Hello", 11, covers[8]);
    albumList.add(a);

    a = new Album("Greatest Hits", 17, covers[9]);
    albumList.add(a);

    adapter.notifyDataSetChanged();
}
}
Bivin
  • 375
  • 3
  • 24
  • Possible duplicate of [RecyclerView every few items are the same - expandable item](http://stackoverflow.com/questions/39097764/recyclerview-every-few-items-are-the-same-expandable-item) – Abbas Oct 19 '16 at 08:13
  • @Abbas I think you have posted a work around. Please check below my answer it is the correct way. You can also check this link:http://stackoverflow.com/questions/37629004/selected-image-button-changes-its-position-in-recyclerview-when-scrolling/37630203#37630203 – Gaurav Singh Oct 19 '16 at 09:34

2 Answers2

2

In your Album model class add a boolean flag say: isExpanded and add getter setter for the same lets assume them as :

// Getter for isExpanded flag
public boolean isExpanded() {
 return isExpanded;
}

// setter for isExpanded flag
public void setIsExpanded(boolean flag) {
 isExpanded = flag;
}

Then do following in your onBindViewHolder method:

@Override
public void onBindViewHolder(final MyViewHolder holder, final int position){

 final Album album = albumList.get(position);
 holder.title.setText(album.getName());
 holder.count.setText(album.getNumOfSongs() + " songs");

 if(album.isExpanded()) {

   holder.expandableLayout11.expand();

   } else {

   holder.expandableLayout11.collapse();
   }

 holder.title.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
      // toggle view
      holder.expandableLayout11.toggle();
      // toggle isExpanded flag
      album.setIsExpanded( ! album.isExpanded() )
  }
}
Gaurav Singh
  • 2,200
  • 16
  • 30
  • Thanks for your comment, how do you think mine is a workaround, yours work on the same principles as mine. – Abbas Oct 19 '16 at 11:40
  • @Abbas you are setting duration to 0 which means time up to which view animation should last. But mine solution is as per recycler view documentation which states that we need specify each state of view whether its related to the content in each row or it visibility. – Gaurav Singh Oct 19 '16 at 12:59
  • If you read close enough I did mention adding a state list *"for that you'll need to associate a state with each item in adapter's list."*. – Abbas Oct 19 '16 at 13:03
  • @Abbas Oh! my bad – Gaurav Singh Oct 20 '16 at 11:05
0

Items in RecyclerView is reused. So you should save the position of expandable items.
Then change the state of expandableLayout when row load

int[] expandablePositionArray; // define int array for save all position of expandable items

public AlbumsAdapter(Context mContext, List<Album> albumList ) {
    this.mContext = mContext;
    this.albumList = albumList;
    // init int array
    expandablePositionList = new int[albumList.size()];
}

@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
   ...

   // expand or collapse expandableLayout11 when row load base on expandable position 
   if(expandablePositionList[position] == 1){
       holder.expandableLayout11.expand();
   }else{
       holder.expandableLayout11.collapse();
   }

    holder.title.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View view) {
          holder.expandableLayout11.toggle();

          // save the position of expandable row
          if(expandablePositionList[position] == 1){
               expandablePositionList[position] = 0;
          }else{
               expandablePositionList[position] = 1;
          }
    }
}
Linh
  • 57,942
  • 23
  • 262
  • 279