Как сделать список RecyclerView с раскрывающимися карточками, содержащими дочерние элементы с использованием ViewType?
написал вот такую реализацию списка с раскрывающимися карточками. Внутри каждой карточки свой список. Реализовано это с помощью двух ViewType. Первый для заголовка секции, второй для элемента списка. Но при раскрытии элементы списка перемешиваются. Элементы из первой секции перемещаются во вторую, а элементы из третьей секции в первую. Не знаю как исправить. Мне нужно чтобы по тапу на нужную секцию она раскрывалась, а по тапу на следующую секцию, ее элементы не попадали в предыдущую. Ниже будет код который я написал сам. Так как не смог найти никакой подобной реализации в Google. Важно: Библиотеки сторонние использовать нельзя!
Здесь происходит генерация элементов для списка.
object DataGenerator {
val items = mutableListOf<ListItem>()
val first = mutableListOf<TextItem>()
val second = mutableListOf<TextItem>()
val last = mutableListOf<TextItem>()
init {
for (i in 1..2) {
first.add(TextItem("Only Blue title", "Content 1"))
}
for (i in 1..2) {
second.add(TextItem("Only Red title", "Lorem ipsum dolor sit ament"))
}
for (i in 1..2) {
last.add(TextItem("Title 2", "Content 2"))
}
items.add(HeaderItem("Header item 1", first, false))
items.add(HeaderItem("Header item 2", second, false))
items.add(HeaderItem("Header item 3", last, false))
}
}
Интерфейс ListItem является общим для обоих типов элементов.
interface ListItem
HeaderItem - заголовок секции, реализует ListItem
data class HeaderItem(
val title: String,
val items: List<TextItem>,
var expanded: Boolean = false
): ListItem
Далее идет TextItem, который также реализует ListItem и является элементом дочернего списка.
data class TextItem(
val title: String,
val content: String,
): ListItem
А также имеется класс адаптера, в методе onBindViewHolder которого я написал код, добавления и удаления элементов секции по тапу на заголовок. Вот с ним как раз и проблема.
class SectionedAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var items = mutableListOf<ListItem>()
fun setItems(items: MutableList<ListItem>) {
this.items = items
notifyDataSetChanged()
}
class HeaderItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(item: HeaderItem) = with(itemView) {
textViewHeader.text = item.title
}
}
class TextItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(item: TextItem) = with(itemView) {
textViewTitle.text = item.title
textViewContent.text = item.content
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when(viewType) {
TYPE_HEADER -> {
val headerView = LayoutInflater.from(parent.context).inflate(R.layout.item_header, parent, false)
return HeaderItemViewHolder(headerView)
}
TYPE_TEXT -> {
val textView = LayoutInflater.from(parent.context).inflate(R.layout.item_text, parent, false)
return TextItemViewHolder(textView)
}
else -> throw IllegalArgumentException()
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item = items[position]
when(holder) {
is HeaderItemViewHolder -> {
holder.bind(item as HeaderItem)
holder.itemView.setOnClickListener {
if(item.expanded) {
items.addAll(position + 1, item.items)
notifyItemRangeInserted(position + 1, item.items.size)
}
else {
items.removeAll(item.items)
notifyItemRangeRemoved(position - 1, item.items.size)
}
item.expanded = !item.expanded
}
}
is TextItemViewHolder -> {
holder.bind(item as TextItem)
}
else -> throw IllegalArgumentException()
}
}
override fun getItemCount(): Int {
return items.count()
}
override fun getItemViewType(position: Int): Int {
val item = items[position]
return when(item) {
is HeaderItem -> TYPE_HEADER
is TextItem -> TYPE_TEXT
else -> throw IllegalArgumentException()
}
}
companion object {
const val TYPE_HEADER = 0
const val TYPE_TEXT = 1
}
}
Буду рад любой помощи. Бьюсь с этим уже третью неделю. Смотрел в сторону библиотек, но у реализации на ViewType производительность выше. Чем если использовать ту же библиотеку Groupie. Не хочу создавать второй вложенный в карточку RecyclerView. Это приведет к лагам и потере кадров. PS уже тестировал этот вариант
Полный код залил на гит, можете скачать, запустить, воспроизвести баг https://gitlab.com/fursa.ilya/recyclerview