Collapsing CardView Animation работает неправильно
То, что я пытаюсь сделать
У меня есть RecyclerView
со многими элементами, которые в основном являются CardView
.
У этих карт есть поддерживающий текст в середине их тел, который по умолчанию имеет видимость GONE
по умолчанию, и он сделал VISIBLE
когда я нажимаю стрелку справа от карты.
Я пытаюсь анимировать карту, пока текст раскрывается, и когда он рухнул.
На приведенном ниже рисунке показана расширенная карта и свернутая карта:
Макет CardView
(я удалил некоторые части для удобочитаемости):
<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>
Эта проблема
Анимация работает, когда карта расширяется и раскрывает тело TextView
, однако, когда я пытаюсь свернуть его, карты под анимированным перекрывают первый.
Пример:
То, что я пробовал до сих пор
Я уже задал аналогичный вопрос об этом поведении здесь раньше, но это решение не работает для TextView
в середине карты.
Код, который отвечает за часть анимации, находится внутри адаптера RecyclerView
. Стрелка имеет прослушиватель кликов, который вызывает метод ниже:
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
}
}
Где root
- мой CardView
.
Я также попытался использовать LinearLayout
вместо самой карты для задержанного перехода, но это тоже не сработало.
Как я могу достичь этого поведения для моего макета?
Ответы
Ответ 1
Вам придется выполнить переход на RecyclerView, а не на отдельные элементы. В противном случае изменения макета RecyclerView не учитываются при автоматическом переходе, потому что он будет рассматривать только те изменения в этом очень детском представлении, хотя на самом деле косвенное влияние оказывают другие зрители (параметры макета меняются).
Таким образом, вместо передачи "root" (вид элемента) в TransitionManager # beginDelayedTransition передайте ссылку на ваш RecyclerView
Ответ 2
Я бы посоветовал вам использовать рамки Animator и применить анимацию высоты к вашему TextView.
Вот хорошая библиотека, которую вы можете использовать: https://github.com/cachapa/ExpandableLayout
Я также предлагаю вам проверить его исходный код, он использует аниматоры
Ответ 3
RecyclerView ведет себя странно, если его элементы изменяются вне обратных вызовов RecyclerViews. Попробуйте использовать adapter.notifyItemChanged (позиция, полезная нагрузка) и обновите элемент:
Замените адаптер onclick следующим:
adapter.notifyItemChanged(adapterPosition, true) // needs adapter reference, can use more meaningful payload
Затем внутри вашего адаптера:
override fun onBindViewHolder(holder: Holder, position: Int, payloads: List<Any>) {
if (payloads.isEmpty())
onBindViewHolder(holder, position)
else
holder.toggleVisibility()
}
Вы также можете увидеть, что происходит при запуске delayedTransition на LinearLayout вместо самой карты.
Это не будет идеально, но это вызовет анимацию следующих предметов, а не прыжков и отсечения.
Ответ 4
Может быть, уже слишком поздно. Внутри onBindViewHolder() есть это
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
}
Ответ 5
Вы должны применить TransitionManager.beginDelayedTransition
в корневом представлении, в котором содержится карта
Вы должны удалить android:animateLayoutChanges="true"
со всей компоновки
TransitionManager.beginDelayedTransition(the_root_view_where_card_view_exist, new AutoTransition());