Recyclerview Expand/Collapse Items

How to handle expandable ViewHolders in a RecyclerView?

You should not iterate all views. You need just save index of expanded view and call notifyDataSetChanged or notifyItemChanged.

private int expandedItemIndex = -1;

@Override
protected void onBindViewHolder(@NonNull BrewViewHolder holder,
final int position, @NonNull Brew brew) {

// Bind Views
holder.bind(brew);

// Set expander ClickListener
holder.card.setOnClickListener(v -> {
if (position == expandedItemIndex) {
notifyItemChanged(position);
expandedItemIndex = -1;
} else {
if (expandedItemIndex != -1) {
notifyItemChanged(expandedItemIndex);
}
expandedItemIndex = position;
notifyItemChanged(position);
}
});

if (position == expandedItemIndex) {
// Expand
holder.quickActions.setVisibility(View.VISIBLE);
} else {
// Collapse
holder.quickActions.setVisibility(View.GONE);
}
}

Recyclerview expand/collapse a number of items

This should be easy to do right within your adapter.

  • Add a flag to your adapter class:

        private boolean mExpanded;
  • Add a new method to call when the button is clicked:

        public void setExpanded(boolean expanded) {
    mExpanded = expanded;
    notifyDataSetChanged();
    }
  • Then modify your getItemCount method something like this:

        @Override
    public int getItemCount() {
    return mExpanded ? itemlist.size() : 3;
    }

It doesn't matter that the rest of the items are still in the adapter list; if you tell the RecyclerView there are only three items, then that's all it will show.

Expand/collapse a nested RecyclerView

Instead of having a new sub Recyclerview for every header you can create a multi view-type adapter that will have a view-type for your header and a view-type for your child-item.

And instead of using a just the header data-item for your list of data, use a generic type that will allow casting each data-type to its own view-type.

To do that we need to create an empty interface that all of our data-types will implement that way they are all generic.

public interface GenericDataType {}

so then your data-type will look like this

class HeaderItem implements GenericDataType {
//All of your pojo data
List<ChildrenItem> childrens; //ChildrenItem will also implement the GenericDataType that way both of the items are acceptable
}

So ones we did that we can replace the current items from

private List<EligibilityDetails> mEligsList;
private List<Items> mItemslist;

To

private List<GenericDataType> adapterItems;

Now we need to make sure that whenever we have a certain ViewHolder the item of that position will be of the right type. In order to do that we need to change our getItemViewType

@Override
public int getItemViewType(int position) {
GenericItem currentItem = adapterItems.get(position);

if (currentItem instanceOf HeaderItem) { //We have to use if else becasue java's switch does not supprt checking instancesOf
return R.layout.your_header_item_layout_id;

} else if(currentItem instanceOf ChildrenItem) {
return R.layout.your_children_item_layout_id;

} else if(repeat for any other types you have) {
return R.layout.your_other_item_layout_id;

} else {
throw new Throwable("Unsupported type"); //This should never happen but we add it to make the compiler compile
}
}

Now we can finally change our onBind method to support both types

@Override
public void onBindViewHolder(@NonNull final EligibilityAdapter.ViewHolder viewHolder, int i) {

if (viewHolder instanceOf HeaderViewHolder) {
HeaderViewHolder holder = (HeaderViewHolder) viewHolder;
headerItem = (HeaderItem) items.get(i);
//Do rest of binding here

holder.viewToAddMoreItems.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!headerItem.isEpanded()) { //Add to your header type a Boolean to check if it is expanded or not
adapterItems.addAll(headerItem.getChildrens()); //They are the same generic type but the getItemViewType will handle it for us
notifyItemRangeInserted(); //Provied item start index and size of the list
} else {
adapterItems.removeAll(headerItem.getChildrens());
notifyItemRangeRemoved(); I don't remember what it require but you'll figure that out
}
headerItem.setExpanded(!headerItem.isExpanded()); //Flipping the value
}
});

} else if (viewHolder instanceOf ChildrenViewHolder) {
ChildrenViewHolder holder = (ChildrenViewHolder) viewHolder;
childrenItem = (ChildrenItem) items.get(i);
//Do your binding here

} else if(repeate for other view-types) {}
}


Related Topics



Leave a reply



Submit