Я обнаружил, что самый простой способ достичь этого - связать model
с ViewHolder
, что я имею в виду под этим.
Мой подход работает путем устранения решения о том, когда заполнять каждый ViewHolder
из адаптера в наш список элементов.
Допустим, мы хотим показать список имен и каждый 5-й элемент, который мы хотим показать (только в качестве примера это может быть что угодно)
val elements = listOf("Name #1", "Name #2", "Name #3", "Name #4", AdModel("our ad"), "Name #5")
Теперь внутри адаптера мы сначала говорим, что расширяем универсальный ViewHolder
класс RecyclerView.Adapter<RecyclerView.ViewHolder>()
.
После этого мы хотим переопределить 3 метода.
getItemViewType
Здесь мы решим, какой файл макета связан с каждым model
, мы сделаем это, используя экземплярпроверяет и возвращает файл макета, который мы хотим показать, основываясь на типе.
override fun getItemViewType(position: Int): Int {
val element = elements[position] // assuming your list is called "elements"
return when (element) {
is String -> R.layout.name_layout_file
is AdModel -> R.layout.ad_layout_file
else -> throw IllegalArgumentException("Unsupported type") // in case populated with a model we don't know how to display.
}
}
onCreateViewHolder
Вам потребуется создать класс ViewHolder
для каждого типа, который вы хотите показать.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
R.layout.name_layout_file -> NameViewHolder(inflater.inflate(viewType, parent, false))
R.layout.ad_layout_file -> AdViewHolder(inflater.inflate(viewType, parent, false))
else -> throw IllegalArgumentException("Unsupported layout") // in case populated with a model we don't know how to display.
}
}
onBindViewHolder
Здесь мы можем легко привести наши ViewHolder
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val element = elements[position] // assuming your list is called "elements"
when (holder) {
is NameViewHolder -> {
val name = element as String
// bind NameViewHolder
}
is AdViewHolder -> {
val adModel = element as AdModel
// bind AdViewHolder
}
}
}
Ваш полный адаптер должен выглядеть следующим образом:
class SampleAdapter(val elements: List<Any>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
R.layout.name_layout_file -> NameViewHolder(inflater.inflate(viewType, parent, false))
R.layout.ad_layout_file -> AdViewHolder(inflater.inflate(viewType, parent, false))
else -> throw IllegalArgumentException("Unsupported layout") // in case populated with a model we don't know how to display.
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val element = elements[position] // assuming your list is called "elements"
when (holder) {
is NameViewHolder -> {
val name = element as String
// bind NameViewHolder
}
is AdViewHolder -> {
val adModel = element as AdModel
// bind AdViewHolder
}
}
}
override fun getItemViewType(position: Int): Int {
val element = elements[position] // assuming your list is called "elements"
return when (element) {
is String -> R.layout.name_layout_file
is AdModel -> R.layout.ad_layout_file
else -> throw IllegalArgumentException("Unsupported type") // in case populated with a model we don't know how to display.
}
}
}
Когда вы загружаете адаптер, вы загружаете его со списком нескольких типов, и все работает.
Самым большим преимуществом является то, что вы не ограничены определенными типами, и очень просто добавить больше типов представлений.
Но, если вы хотите сохранить всю эту работу, я написалбиблиотека, которая генерирует однотипные / многотипные адаптеры во время компиляции с использованием обработки аннотаций.
Библиотека генерирует все, что вам нужно, включая findViewById
, и оставляет вам минимум кода, необходимого для написания для реализации адаптера.
Вы можете проверить это здесь: Генциклер