buildFeatures {
dataBinding true
}
childDTO.kt
data class ChildDTO(
var title: String? = null,
var description: String? = null,
var imageURL: String? = null
)
ParentDTO.kt
data class ParentDTO(
var title: String? = null,
var description: String? = null,
var children: List<ChildDTO>? = null,
)
object DataFactory {
// to generate random numbers
private val rand = Random(123123123L)
// Sample titles
private val titles = listOf("Vertigo",
"The Innocents",
"Lawrence of Arabia",
"The Deer Hunter",
"Amadeus",
"Blade Runner",
"Eyes Wide Shut"
)
// Sample descriptions
private val descriptions = listOf(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"Pellentesque sagittis odio ut tincidunt scelerisque.",
"Phasellus a neque consequat leo bibendum tempus.",
"Quisque at enim id odio blandit imperdiet nec consequat augue.",
"Cras iaculis lorem a dignissim egestas.",
"Duis quis leo pharetra, vestibulum elit rhoncus, tempus ante.",
"Duis ut lorem aliquet, lobortis massa a, fringilla velit.",
"Fusce non ipsum sed augue gravida ullamcorper."
)
// Returns a sample `ParentDTO` Object
fun getParentList(): List<ParentDTO> {
val list = ArrayList<ParentDTO>()
for (i in 1..rand.nextInt(5, 10)) {
list.add(ParentDTO(
titles[rand.nextInt(titles.size)], descriptions[rand.nextInt(descriptions.size)], getChildList()
))
}
return list
}
// Returns a sample `List<ChildDTO>` Object to populate the parent object
private fun getChildList(): List<ChildDTO> {
val list = ArrayList<ChildDTO>()
for (i in 1..rand.nextInt(5, 10)) {
list.add(getRandomChild())
}
return list
}
// Returns a sample `ChildDTO` Object
private fun getRandomChild(): ChildDTO {
return ChildDTO(
titles[rand.nextInt(titles.size)],
descriptions[rand.nextInt(descriptions.size)],
"@mipmap/img_sample"
)
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="data"
type="com.rishabh.nestedrecyclerview.dtos.ChildDTO" />
</data>
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="4dp"
android:layout_marginVertical="4dp"
android:elevation="4dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="200dp"
android:layout_height="wrap_content"
android:background="@color/design_default_color_secondary"
android:paddingHorizontal="8dp"
android:paddingVertical="8dp">
<ImageView
android:id="@+id/iv_sub_image"
android:layout_width="46dp"
android:layout_height="46dp"
android:contentDescription="@string/sublist_image"
android:src="@mipmap/img_sample"
android:textColor="@color/black"
android:visibility="@{data.imageURL.isEmpty() ? View.GONE : View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/avatars" />
<TextView
android:id="@+id/tv_sub_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="@{data.title}"
android:textColor="@color/black"
android:textStyle="bold"
app:layout_constraintStart_toEndOf="@+id/iv_sub_image"
app:layout_constraintTop_toTopOf="parent"
tools:text="Sample Child Title" />
<TextView
android:id="@+id/tv_sub_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:lines="2"
android:text="@{data.description}"
android:textColor="@color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/iv_sub_image"
app:layout_constraintTop_toBottomOf="@+id/tv_sub_title"
tools:text="Sample Child Description" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</layout>
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="data"
type="com.rishabh.nestedrecyclerview.dtos.ParentDTO" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="6dp"
android:paddingHorizontal="8dp"
android:paddingVertical="8dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textColor="#FF0000"
android:fontFamily="monospace"
android:textStyle="bold"
android:text="@{data.title}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Sample Parent Title" />
<TextView
android:id="@+id/tv_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:text="@{data.description}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title"
tools:text="Sample Parent Description" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_children"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_description"
tools:listitem="@layout/child_item" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
<?xml version="1.0" encoding="utf-8"?>
<layout>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingHorizontal="8dp"
android:paddingVertical="8dp"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_items"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="@layout/parent_item" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
class ChildAdapter(private val childData: List<ChildDTO>?) : RecyclerView.Adapter<ViewHolder>() {
inner class ViewHolder(private val itemView: View, val binding: ChildItemBinding) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = DataBindingUtil.inflate(LayoutInflater.from(parent.context),
R.layout.child_item, parent, false) as ChildItemBinding
return ViewHolder(binding.root, binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if ((childData?.size ?: 0) > position)
holder.binding.data = childData?.get(position)
holder.binding.executePendingBindings()
}
override fun getItemCount() = childData?.size ?: 0
}
class ParentAdapter(private val data: List<ParentDTO>) : RecyclerView.Adapter<ViewHolder>() {
inner class ViewHolder(private val itemView: View, val binding: ParentItemBinding) : RecyclerView.ViewHolder(itemView) {}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = DataBindingUtil.inflate(LayoutInflater.from(parent.context),
R.layout.parent_item, parent, false) as ParentItemBinding
return ViewHolder(binding.root, binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.binding.data = data[position]
holder.binding.rvChildren.adapter = ChildAdapter(data[position].children)
holder.binding.executePendingBindings()
}
override fun getItemCount() = data.size
}
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
val data = DataFactory.getParentList()
binding.rvItems.adapter = ParentAdapter(data)
}
}