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.