Reputation: 11497
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:
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 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:
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?
Upvotes: 14
Views: 4090
Reputation: 21
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());
Upvotes: 2
Reputation:
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
}
Upvotes: 0
Reputation: 281
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
Upvotes: 5
Reputation: 17268
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.
Upvotes: 1
Reputation: 8585
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
Upvotes: 0