RecyclerView Animation on Item Click
Asked Answered
K

2

23

I am trying to implement my own recyclerview Animation - I would like to achieve this without using any external libraries. Here is what the theoretical animation should look like.

enter image description here

The user clicks an item on the List and an animation occurs which opens up another View.

On a high level with minimal code, possibly just pseudo code what would the process be in order to create some animation like that?

Also I would like to note that the animation should be able to be done in reverse as well if the user clicks the same item or another item

I am not that familiar with the RecyclerView class and would like to learn more about it and any animations associated with it.

Kami answered 24/12, 2014 at 22:22 Comment(3)
Have you seen this question?Mima
I think you will need to do the research by your own and post specific question after that. For me this is just a too big question and brings any research in it just a this should it look like how can i get it work. My opinion. Merry Christmas to you anyway! ;)Polyhymnia
Tanis thank you I have not seen that question, but my line of thinking was correct in that ViewHolder is emphasized a lot more in RecyclerView - so what I am thinking is to write a custom view to hold the expanded layout and bind an onItemClickListener or onItemTouchListener to the list item.Kami
K
15

Solution:

The way I solved this problem was to implement a listener View.OnClickListener to the ViewHolder class which extends RecyclerView.ViewHolder. So we get the following code:

public static class ExampleViewHolder extends RecyclerView.ViewHolder 
    implements View.OnClickListener {

    private int originalHeight = 0;
    private boolean isViewExpanded = false;
    private YourCustomView yourCustomView

    // ..... CODE ..... //

}

The variables originalHeight and isViewExpanded are used in the animation process. In the constructor I initialize the view to the View.OnClickListener like so:

public ExampleViewHolder(View v) {
     super(v);
     v.setOnClickListener(this);

     // Initialize other views, like TextView, ImageView, etc. here

     // If isViewExpanded == false then set the visibility 
     // of whatever will be in the expanded to GONE

     if (isViewExpanded == false) {
         // Set Views to View.GONE and .setEnabled(false)
         yourCustomView.setVisibility(View.GONE);
         yourCustomView.setEnabled(false);
     }

 }

Now that the constructor has been taken care of we want to configure what happens when the user clicks on an individual RecyclerView item. The classes that will be useful here would be the ValueAnimator and the Animation objects. We override the onClick method like so to accomplish this:

@Override
public void onClick(final View view) {
    // If the originalHeight is 0 then find the height of the View being used 
    // This would be the height of the cardview
    if (originalHeight == 0) {
            originalHeight = view.getHeight();
        }

    // Declare a ValueAnimator object
    ValueAnimator valueAnimator;
        if (!mIsViewExpanded) {
            yourCustomView.setVisibility(View.VISIBLE);
            yourCustomView.setEnabled(true);
            mIsViewExpanded = true;
            valueAnimator = ValueAnimator.ofInt(originalHeight, originalHeight + (int) (originalHeight * 2.0)); // These values in this method can be changed to expand however much you like
        } else {
            mIsViewExpanded = false;
            valueAnimator = ValueAnimator.ofInt(originalHeight + (int) (originalHeight * 2.0), originalHeight);

            Animation a = new AlphaAnimation(1.00f, 0.00f); // Fade out

            a.setDuration(200);
            // Set a listener to the animation and configure onAnimationEnd
            a.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {

                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    yourCustomView.setVisibility(View.INVISIBLE);
                    yourCustomView.setEnabled(false);
                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });

            // Set the animation on the custom view
            yourCustomView.startAnimation(a);
        }
        valueAnimator.setDuration(200);
        valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            public void onAnimationUpdate(ValueAnimator animation) {
                Integer value = (Integer) animation.getAnimatedValue();
                view.getLayoutParams().height = value.intValue();
                view.requestLayout();
            }
        });


        valueAnimator.start();

    }

Now when you touch an individual cardview on the RecyclerView (assuming you have a CardView setup then it should expand out. Make sure to declare your customView properly in your xml file (example if you want the CardView to expand down when you touch it then properly assign the customView underneath the other views and set the visibility to gone when you declare it and then when the animation starts like so in the code above then set the visibility to Visible and enable the view.

Hope this can help someone out.

Kami answered 2/1, 2015 at 2:48 Comment(3)
Thanks for this AndyRoid! It's really helpful for me. In my case the height of the CardView differs per item, but the 'CustomView' is the same for all items. Is it possible to calculate the necessary height for the card to fully expand without it being visible? Using a originalHeight * x doesn't work in my case.Jugal
Why thanks ? if you have more items, bug to screen up or down, please use tags :)Spavin
I use a similar solution, but have a problem. All the views that are below the expanding one just snap into place, but I want them to smoothly move down. @Kami , do you have the same behaviour?Potiche
A
4

An easier alternative for @AndyRoid's answer is to use android:animateLayoutChanges="true" property. This way you don't need to write any animation code; however, this is not a way to go if you need to have a control over animation.

You still need to create an OnClickListener:

class CardTapListener implements View.OnClickListener {
    @Override
    public void onClick(View v) {
        View someView = v.findViewById(R.id.view_to_expand);

        if (someView.getVisibility() == View.GONE) {
            someView.setVisibility(View.VISIBLE);
        }
        else if (someView.getVisibility() == View.VISIBLE){
            someView.setVisibility(View.GONE);
        }

    }
}

Attach it to every ViewHolder:

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.view_holder_layout, viewGroup, false);
    v.setOnClickListener(new CardTapListener());
    return new ItemViewHolder(v);
}

Don't forget to collapse views when binding a new item:

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
    ...
    // Collapse (probably opened by user previously) view
    ItemViewHolder itemHolder = (ItemViewHolder) viewHolder;
    itemHolder.description.setVisibility(View.GONE);
    ...

}

view_holder_layout.xml:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:animateLayoutChanges="true"
    android:orientation="vertical">

 ...

    <AnyViewHere
        android:visibility="gone"
        android:id="@+id/view_to_expand" />

 </LinearLayout>
Arrow answered 27/6, 2015 at 11:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.