Problem
I want to have a RecyclerView with width=match_parent and height=wrap_content. I need to display items horizontally so I use a proper LinearLayoutManager.
I face a problem with a RecyclerView behaviour. The items of my list have different content (some values are present, other are absent in different items), thus the height of my items can vary. And when I scroll the list and further items have bigger content than first items, the height of a RecyclerView doesn't adjust to display its children properly, but it cuts their content. It could work only if the first item is the biggest one.
Research
I saw some old question from 2016 when people had some similar issues. Most of the solutions recommend to update the recyclerView version to 'com.android.support:recyclerview-v7:23.2.1'. But nowadays we use Androidx. The current stable version for recyclerView is 1.0.0 I tried 1.1.0-rc1 but got the same result.
Also, I tried to setAutoMeasureEnabled(true) for my LinearLayoutManager, but it doesn't work as well.
My Workaround
So finally I tried to update the ViewHolder view not directly by assigning values to TextViews, but through view.post(Runnable {}). And it works, I don't know exactly why.
Working example GIF - with a help of view.post(Runnable {})
The expected behaviour is shown on a second GIF: as soon as we scroll to the item with a bigger content, the view size gets updated and recyclerView height gets updated as well.
My Question
Do you think the above workaround is okay? Maybe you have some more intelligent ideas / approaches? Thank you for help and attention.
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#C5C510" />
</FrameLayout>
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="200dp"
android:layout_height="wrap_content">
<TextView
android:id="@+id/itemTextView1"
android:layout_width="match_parent"
android:textSize="40dp"
tools:text="dsgsdfgsdf"
android:gravity="center"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/itemTextView2"
android:layout_width="match_parent"
android:textSize="40dp"
tools:text="dsgsdfgsdf"
android:gravity="center"
android:visibility="gone"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/itemTextView3"
android:layout_width="match_parent"
android:textSize="40dp"
tools:text="dsgsdfgsdf"
android:gravity="center"
android:visibility="gone"
android:layout_height="wrap_content"/>
</LinearLayout>
MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
recyclerView.layoutManager =
LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
recyclerView.adapter = Adapter(100) // 100 is the number of items to be displayed, adapter generates them
}
}
Adapter snippet (Default, Doesn't work as expected):
override fun onBindViewHolder(holder: ViewHolder, pos: Int) {
holder.itemView.itemTextView1.text = "String \n" + pos.toString()
holder.itemView.itemTextView2.text = "String \n" + pos.toString()
holder.itemView.itemTextView3.text = "String \n" + pos.toString()
holder.itemView.itemTextView2.visibility = if (pos > 10) View.VISIBLE else View.GONE
holder.itemView.itemTextView3.visibility = if (pos > 30) View.VISIBLE else View.GONE
}
Adapter snippet (Makes the RecyclerView work as expected):
override fun onBindViewHolder(holder: ViewHolder, pos: Int) {
holder.itemView.post {
holder.itemView.itemTextView1.text = "String \n" + pos.toString()
holder.itemView.itemTextView2.text = "String \n" + pos.toString()
holder.itemView.itemTextView3.text = "String \n" + pos.toString()
holder.itemView.itemTextView2.visibility = if (pos > 10) View.VISIBLE else View.GONE
holder.itemView.itemTextView3.visibility = if (pos > 30) View.VISIBLE else View.GONE
}
}