RecyclerView: фильтр отображения единственной коллекции
Есть рабочий Adapter: RecyclerView.Adapter
Но он отображает весь список arr
Я же хочу, чтобы он отображал только элементы при условии (пример), что поле элемента Tovar.coast > 100
Я знаю, что можно создать новый List с этим условием и отобразить его.
Но можно ли как-то сделать это на имеющимся массиве, без создания нового?
class TovarAdapter(
var app: AppCompatActivity,
var arr: MutableList<Tovar>
) : RecyclerView.Adapter<TovarAdapter.MyHolder>() {
class MyHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
val infalter = LayoutInflater.from(parent.context)
val itemView = infalter.inflate(R.layout.item_tovar, parent, false)
val holder = MyHolder(itemView)
return holder
}
override fun getItemCount(): Int {
return arr.size
}
override fun onBindViewHolder(holder: MyHolder, position: Int) {
holder.itemView.findViewById<TextView>(R.id.item_name_tx).setText("${arr[position].name}")
}
суть моей проблемы:
есть список товаров (класс). у каждого объекта есть поля "имя, цена, избранное (boolean)"
товары можно "добавлять / удалять / редактировать"
есть кнопка "показать только избранное"
когда она нажимается - на основе основного массива, по критерию "избранное == true" создается новый список товаров и скармилвается Адаптеру.
редактируются эти элементы хорошо. ведь в обоих списках лежат просто ссылки на объекты.
а вот если я включил "показать избранные" и пытаюсь удалить товар - он удаляется только из "временного" массива, созданного для отображения только избранного.
конечно же, я добавил проверку "у нас настоящий массив или временный? если временный - найти и удалить этот объект из настоящего".
но мне этот вариант душу не греет))
Ответы (2 шт):
Хочу поделиться тем, как я реализую адаптер. Идея в том, чтобы в конструкторе не было ваших элементов. Элементы добавляются отдельно, функцией или изменяемым свойством. Это удобное место, что бы фильтровать ваши данные, в зависимости от условий.
class Adapter : RecyclerView.Adapter<Adapter.Holder>() {
var clickListener: ((Client) -> (Unit))? = null
private val _items = mutableListOf<Client?>()
var items: List<Client?>
get() = _items
set(value) {
_items.clear()
// обрабатываейте данные здесь
// например используйте filter { ваше условие }
_items.addAll(value)
notifyDataSetChanged()
}
override fun onBindViewHolder(holder: Holder, position: Int) {
val item = _items[position]
заполняйте view или используйте databinding
view.setOnClickListener {
clickListener?.invoke(item)
}
}
// не забудьте переопределить другие методы
override fun getItemCount() = _items.size
}
Таким образом, вам не нужно создавать новый инстанс, что бы заполнить адаптер другими данными. Теперь у вас есть место, что бы использовать другие методы адаптера, например notifyItemInserted .
Как это использовать в актвити или фрагменте:
class ClientsFragment : Fragment() {
private val adapter by lazy { ClientAdapter() }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// получите данные
adapter.items = it
adapter.clickListener = { client ->
// ваш колбек от слушателя нажатий
}
}
придумал костыль.
как меня и предупреждали в комментах - тормоза UI видны даже при размере массива 5-10 шт.
в методе отображения элементов я добавил блок проверки по нужному критерию и просто задал размеры это View по высоте и ширине = 0. и скрыл ее (хотя это и не обязательно).
так же добавил return чтобы попытаться облегчить муки (хотя это и не очень помогает)
p.s. вылезли большие баги. такой способ явно не подходит, если необходимо еще работать с элементами массива. и особенное с тем критерием элемента, по которому отображаются элементы.
было:
override fun onBindViewHolder(holder: MyHolder, position: Int) {
holder.itemView.findViewById<TextView>(R.id.item_name_tx).setText("${arr[position].name}")
}
стало:
override fun onBindViewHolder(holder: MyHolder, position: Int) {
if (arr[position].coast < 100) {
holder.itemView.layoutParams.height = 0
holder.itemView.layoutParams.width = 0
holder.itemView.visibility = View.GONE
return
}
holder.itemView.findViewById<TextView>(R.id.item_name_tx).setText("${arr[position].name}")
}