Окей, есть несколько хитрых случаев с анимацией видимости. Например, вы можете посмотреть этот пост. Анимация макета не работает при первом запуске
android:animateLayoutChanges="true"
animateLayoutChanges достаточно в большинстве случаев. Но в recyclerView разработчик должен восстановить предыдущее состояние viewHolder, поскольку recyclerView повторно использует держатели вида, поэтому, если вы не проверяете реальное состояние держателя вида в соответствии с положением, это может быть неправильно (например, в двух разных положениях используется один и тот же держатель, и одно из них расширено а другой развалился). Теперь появилась новая проблема, которая заключается в том, что если вы используете анимационные изменения макета, то нет простого способа развернуть или свернуть текст описания без анимации. Вы можете попробовать отключить, включить переход родительского макета, но он не работает для меня.
Другим способом является изменение высоты textViews 0 на TextView.getHeight () или наоборот, но в этом случае вы не знаете высоту textViews, поскольку ее высота равна 0, и вы не хотите расширять ее, если пользователь не щелкнет по ней. Но вы можете найти желаемую высоту TextView. Это рабочий код для меня. Пожалуйста, дайте мне знать, если это вам поможет.
class Adapter : RecyclerView.Adapter<Adapter.Holder>() {
private var expandedHolderPosition = -1
private var itemList = emptyList<Item>()
private var getViewHolder: (position: Int) -> Holder? = { null }
override fun getItemCount() = itemList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val inflatedView = parent.inflate(R.layout.item, false)
return Holder(inflatedView)
}
override fun onBindViewHolder(holder: Holder, position: Int) {
val currentItem = itemList[position]
holder.bindItem(currentItem)
}
fun updateList(items: List<Item>) {
this.expandedHolderPosition = -1
this.itemList = items
this.notifyDataSetChanged()
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
getViewHolder = { position ->
recyclerView.findViewHolderForAdapterPosition(position) as? Holder
}
}
inner class Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val textTitle = itemView.textTitle
private val textDescription = itemView.textDescription
private var desiredTextViewHeight = 0
private val isExpanded get() = adapterPosition == expandedHolderPosition
fun bindItem(item: Item) {
textTitle.text = item.title.toString()
textDescription.setText(item.description)
textDescription.post {
desiredTextViewHeight = with(textDescription) {
lineHeight * lineCount + layout.bottomPadding - layout.topPadding
}
if (isExpanded) {
showDescription(false)
} else {
hideDescription(false)
}
}
itemView.setOnClickListener {
val position = adapterPosition
//Its in open state close it.
if (isExpanded) {
expandedHolderPosition = -1
hideDescription(true)
} else {
getViewHolder(expandedHolderPosition)?.hideDescription(true)
showDescription(true)
expandedHolderPosition = position
}
}
}
private fun hideDescription(animate: Boolean) {
logDebug("hideDescription")
if (animate) {
changeHeightWithAnimation(desiredTextViewHeight, 0)
} else {
updateDescriptionHeight(0)
}
}
private fun showDescription(animate: Boolean) {
logDebug("showDescription")
if (animate) {
changeHeightWithAnimation(0, desiredTextViewHeight)
} else {
updateDescriptionHeight(desiredTextViewHeight)
}
}
private fun changeHeightWithAnimation(from: Int, to: Int) {
val animator = ValueAnimator.ofInt(from, to)
animator.duration = 300
animator.addUpdateListener { animation: ValueAnimator ->
updateDescriptionHeight(animation.animatedValue as Int)
}
animator.start()
}
private fun updateDescriptionHeight(newHeight: Int) {
textDescription.updateLayoutParams<ViewGroup.LayoutParams> {
height = newHeight
}
}
}
}
data class Item(val title: Int, @StringRes val description: Int = R.string.lorem)
Файл макета для пользовательского элемента.
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:orientation="vertical">
<TextView
android:id="@+id/textTitle"
android:layout_width="match_parent"
android:layout_height="48dp"
android:gravity="center_vertical"
tools:text="Title" />
<TextView
android:id="@+id/textDescription"
android:layout_width="match_parent"
android:layout_height="0dp"
android:gravity="center_vertical"
tools:layout_height="wrap_content"
tools:text="Description" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>