Collapsing CardView Animation not working correctly
Asked Answered
B

5

14

What I'm trying to do

I have a RecyclerView with many items that are basically some CardView.

Those cards have a supporting text in the middle of their bodies, which has the visibility set to GONE by default, and it's made VISIBLE when I click the arrow on the right of the card.

I'm trying to animate the card while the text is revealed and while it's collapsed.

The picture below shows the expanded card and the collapsed one:

cards

The CardView layout (I've removed some parts for readability):

<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    card_view:cardCornerRadius="3dp"
    card_view:cardElevation="4dp"
    card_view:cardUseCompatPadding="true"
    android:id="@+id/root">

    <LinearLayout
        android:id="@+id/item_ll"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="@dimen/activity_vertical_margin">

        <!-- The header with the title and the item -->


        <TextView
            android:id="@+id/body_content"
            style="@style/TextAppearance.AppCompat.Medium"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="8dp"
            android:layout_marginBottom="8dp"
            android:text="@string/about_page_description"
            android:textColor="@color/secondaryText"
            android:visibility="gone"/>

        <!-- The divider, and the footer with the timestamp -->

    </LinearLayout>
</android.support.v7.widget.CardView>

The problem

The animations is working when the card is expanding and revealing the body TextView, however, when I try to collapse it back, the cards below the animated one overlaps the first one.

Example:

card animation

What I've tried so far

I've already asked a similar question about this behavior here before, but that solution is not working for a TextView in the middle of the card.

The code that's responsible for the animation part is inside the RecyclerView adapter. The arrow has a click listener that calls the method below:

private fun toggleVisibility() {
    if (bodyContent.visibility == View.GONE || bodyContent.visibility == View.INVISIBLE) {
        btSeeMore.animate().rotation(180f).start()
        TransitionManager.beginDelayedTransition(root, AutoTransition())
        bodyContent.visibility = View.VISIBLE
    }
    else {
        btSeeMore.animate().rotation(0f).start()

        TransitionManager.beginDelayedTransition(root, AutoTransition())
        bodyContent.visibility = View.GONE
    }
}

Where root is my CardView.

I've also tried to use the LinearLayout instead of the card itself for the delayed transition, but that didn't work either.

How can I achieve that behavior for my layout?

Bister answered 1/3, 2018 at 17:1 Comment(2)
Have you tried to animate height of the text view manually?Freewill
I haven't. Since the delayedTransition was working for the previous layout, I didn't think it was necessary, until now...Bister
I
5

You will have to perform the transition on the RecyclerView, not on individual items. Otherwise, the RecyclerView layout changes aren't taken into account by the auto transition, because it will only look at what changes in that very child view, even though in fact, other ViewHolders are indirectly affected (layout parameters are changing).

So, instead of passing "root" (the item view) to TransitionManager#beginDelayedTransition, pass a reference to your RecyclerView

Infirmity answered 6/4, 2018 at 23:23 Comment(0)
G
2

You have to apply TransitionManager.beginDelayedTransition on the root view where the cardview is contained

You have to remove android:animateLayoutChanges="true" from all over the layout

TransitionManager.beginDelayedTransition(the_root_view_where_card_view_exist, new AutoTransition());
Get answered 31/8, 2018 at 9:59 Comment(0)
A
1

RecyclerView does behave oddly if his items are resizing outside RecyclerViews callbacks. Try using adapter.notifyItemChanged(position, payload) and updating the item then:

Replace adapter's onclick with this:

adapter.notifyItemChanged(adapterPosition, true) // needs adapter reference, can use more meaningful payload

Then inside of your adapter:

override fun onBindViewHolder(holder: Holder, position: Int, payloads: List<Any>) {
    if (payloads.isEmpty())
        onBindViewHolder(holder, position)
    else
        holder.toggleVisibility()
}

You can also see what happens when running delayedTransition on LinearLayout instead of Card itself.

This won't be perfect, but it will trigger animation of following items instead of them jumping and clipping.

Astra answered 1/3, 2018 at 17:54 Comment(0)
F
0

I would recomment you to use Animator framework and apply height animation to your TextView.

Here is a nice library you can use: https://github.com/cachapa/ExpandableLayout

I also suggest you to check it's source code, it uses the Animators

Freewill answered 1/3, 2018 at 17:48 Comment(0)
I
0

Maybe this is too late. Inside onBindViewHolder() include this

holder.view.btSeeMore.setOnClickListener { view ->
    val seeMore = (bodyContent.visibility != View.VISIBLE)
    view.animate().rotation(if (seeMore) 180f else 0f).start()
    bodyContent.visibility = if (seeMore) View.VISIBLE else View.GONE
}
Isochronous answered 5/6, 2018 at 21:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.