RecyclerView expand/collapse items RecyclerView expand/collapse items android android

RecyclerView expand/collapse items


Please don't use any library for this effect instead use the recommended way of doing it according to Google I/O. In your recyclerView's onBindViewHolder method do this:

final boolean isExpanded = position==mExpandedPosition;holder.details.setVisibility(isExpanded?View.VISIBLE:View.GONE);holder.itemView.setActivated(isExpanded);holder.itemView.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        mExpandedPosition = isExpanded ? -1:position;        TransitionManager.beginDelayedTransition(recyclerView);        notifyDataSetChanged();    }});
  • Where details is my view that will be displayed on touch (call details in your case. Default Visibility.GONE).
  • mExpandedPosition is an int variable initialized to -1

And for the cool effects that you wanted, use these as your list_item attributes:

android:background="@drawable/comment_background"android:stateListAnimator="@animator/comment_selection"

where comment_background is:

<selectorxmlns:android="http://schemas.android.com/apk/res/android"android:constantSize="true"android:enterFadeDuration="@android:integer/config_shortAnimTime"android:exitFadeDuration="@android:integer/config_shortAnimTime"><item android:state_activated="true" android:drawable="@color/selected_comment_background" /><item android:drawable="@color/comment_background" /></selector>

and comment_selection is:

<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:state_activated="true">    <objectAnimator        android:propertyName="translationZ"        android:valueTo="@dimen/z_card"        android:duration="2000"        android:interpolator="@android:interpolator/fast_out_slow_in" /></item><item>    <objectAnimator        android:propertyName="translationZ"        android:valueTo="0dp"        android:duration="2000"        android:interpolator="@android:interpolator/fast_out_slow_in" /></item></selector>


For this, just needed simple lines not complicated

in your onBindViewHolder method add below code

final boolean isExpanded = position==mExpandedPosition;holder.details.setVisibility(isExpanded?View.VISIBLE:View.GONE);holder.itemView.setActivated(isExpanded);holder.itemView.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        mExpandedPosition = isExpanded ? -1:position;        notifyItemChanged(position);    }});

mExpandedPosition is an int global variable initialized to -1

For those who want only one item expanded and others get collapsed. Use this

first declare a global variable with previousExpandedPosition = -1

then

    final boolean isExpanded = position==mExpandedPosition;    holder.details.setVisibility(isExpanded?View.VISIBLE:View.GONE);    holder.itemView.setActivated(isExpanded);    if (isExpanded)       previousExpandedPosition = position;    holder.itemView.setOnClickListener(new View.OnClickListener() {        @Override        public void onClick(View v) {            mExpandedPosition = isExpanded ? -1:position;            notifyItemChanged(previousExpandedPosition);            notifyItemChanged(position);        }    });


Not saying this is the best approach, but it seems to work for me.

The full code may be found at: Example code at: https://github.com/dbleicher/recyclerview-grid-quickreturn

First off, add the expanded area to your cell/item layout, and make the enclosing cell layout animateLayoutChanges="true". This will ensure that the expand/collapse is animated:

<LinearLayout    android:id="@+id/llCardBack"    android:layout_width="fill_parent"    android:layout_height="wrap_content"    android:background="@android:color/white"    android:animateLayoutChanges="true"    android:padding="4dp"    android:orientation="vertical">    <TextView        android:id="@+id/tvTitle"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_gravity="center|fill_horizontal"        android:padding="10dp"        android:gravity="center"        android:background="@android:color/holo_green_dark"        android:text="This is a long title to show wrapping of text in the view."        android:textColor="@android:color/white"        android:textSize="16sp" />    <TextView        android:id="@+id/tvSubTitle"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_gravity="center|fill_horizontal"        android:background="@android:color/holo_purple"        android:padding="6dp"        android:text="My subtitle..."        android:textColor="@android:color/white"        android:textSize="12sp" />    <LinearLayout        android:id="@+id/llExpandArea"        android:visibility="gone"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:gravity="center"        android:orientation="horizontal">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="6dp"            android:text="Item One" />        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_margin="6dp"            android:text="Item Two" />    </LinearLayout></LinearLayout>

Then, make your RV Adapter class implement View.OnClickListener so that you can act on the item being clicked. Add an int field to hold the position of the one expanded view, and initialize it to a negative value:

private int expandedPosition = -1;

Finally, implement your ViewHolder, onBindViewHolder() methods and override the onClick() method. You will expand the view in onBindViewHolder if it's position is equal to "expandedPosition", and hide it if not. You set the value of expandedPosition in the onClick listener:

@Overridepublic void onBindViewHolder(RVAdapter.ViewHolder holder, int position) {    int colorIndex = randy.nextInt(bgColors.length);    holder.tvTitle.setText(mDataset.get(position));    holder.tvTitle.setBackgroundColor(bgColors[colorIndex]);    holder.tvSubTitle.setBackgroundColor(sbgColors[colorIndex]);    if (position == expandedPosition) {        holder.llExpandArea.setVisibility(View.VISIBLE);    } else {        holder.llExpandArea.setVisibility(View.GONE);    }}@Overridepublic void onClick(View view) {    ViewHolder holder = (ViewHolder) view.getTag();    String theString = mDataset.get(holder.getPosition());    // Check for an expanded view, collapse if you find one    if (expandedPosition >= 0) {        int prev = expandedPosition;        notifyItemChanged(prev);    }    // Set the current position to "expanded"    expandedPosition = holder.getPosition();    notifyItemChanged(expandedPosition);    Toast.makeText(mContext, "Clicked: "+theString, Toast.LENGTH_SHORT).show();}/** * Create a ViewHolder to represent your cell layout * and data element structure */public static class ViewHolder extends RecyclerView.ViewHolder {    TextView tvTitle;    TextView tvSubTitle;    LinearLayout llExpandArea;    public ViewHolder(View itemView) {        super(itemView);        tvTitle = (TextView) itemView.findViewById(R.id.tvTitle);        tvSubTitle = (TextView) itemView.findViewById(R.id.tvSubTitle);        llExpandArea = (LinearLayout) itemView.findViewById(R.id.llExpandArea);    }}

This should expand only one item at a time, using the system-default animation for the layout change. At least it works for me. Hope it helps.