RecyclerView многосоставной

107
07 ноября 2019, 21:20

Нужно реализовать RecyclerView в котором должен быть заголовок и под ним список который зависит от данных БД. По началу сделал несколько RecyclerView на одном активити но считаю это не правильно и сжирает много данных.

Answer 1

Пример будет на Kotlin. У вас не должно возникнуть проблем

Я использую базовый Adapter и ViewHolder

BaseAdapter

abstract class BaseAdapter<E,
    H : BaseListViewHolder<E>>(val context: Context?, val listener: BaseItemClickListener<E>?)
: RecyclerView.Adapter<H>() {
val items = mutableListOf<E>()
override fun getItemCount(): Int {
    return items.size
}
fun addItem(item: E) {
    items.add(item)
    notifyItemInserted(itemCount - 1)
}
fun addItems(items: List<E>) {
    this.items.addAll(items)
    notifyItemInserted(itemCount - 1)
}
fun updateItems(items: List<E>) {
    if (this.items != items) {
        clearAdapter()
        addItems(items)
    }
}
fun clearAdapter() {
    items.clear()
    notifyDataSetChanged()
   }
        interface BaseItemClickListener<E> {
            fun onItemClick(item: E)
        }
    }

ViewHolder

abstract class BaseListViewHolder<T>(itemView: View, private val listener: BaseItemClickListener<T>?)
: RecyclerView.ViewHolder(itemView), View.OnClickListener {
val context = itemView.context
@SuppressWarnings("unchecked")
override fun onClick(view: View) {
    listener?.onItemClick(view.tag as T)
}
   open fun bindData(item: T) {
        itemView.tag = item
        itemView.setOnClickListener(this)
    }
}

Теперь посмотрим сам Адаптер. Обратите внимание на метод onCreateViewHolder здесь определяет какой ViewHolder будет использоваться

class TestAdapter(context: Context?, listener: BaseItemClickListener<Cvodka>)
    : BaseAdapter<Cvodka, BaseListViewHolder<Cvodka>>(context, listener) {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseCvodkaViewHolder {
        return when (viewType) {
            EnumCvodka.HEADER.id ->
                HeaderItemCvodkaViewHolder(getInflatedItemView(R.layout.item_cvodka_header, parent), listener)
            EnumCvodka.ACHIEVEMENT.id ->
                AchievementTestViewHolder(getInflatedItemView(R.layout.item_achievements, parent), listener)
            else ->
                HeaderItemCvodkaViewHolder(getInflatedItemView(R.layout.item_cvodka_header, parent), listener)
        }
    }
    private fun getInflatedItemView(@LayoutRes layoutId: Int, parent: ViewGroup): View {
        return LayoutInflater.from(context).inflate(layoutId, parent, false)
    }
    override fun onBindViewHolder(holder: BaseListViewHolder<Cvodka>, position: Int) {
        holder.bindData(items[position])
    }
    override fun getItemViewType(position: Int): Int {
        return items[position].getType().id
    }
}

Для него нам нужен базовый ViewHolder. От него будут наследоваться другие ViewHolder-ы

abstract class BaseCvodkaViewHolder(itemView: View, listener: BaseAdapter.BaseItemClickListener<Cvodka>?)
    : BaseListViewHolder<Cvodka>(itemView, listener)

Сам AchievementTestViewHolder

class AchievementTestViewHolder(itemView: View, listener: BaseAdapter.BaseItemClickListener<Cvodka>?)
    : BaseCvodkaViewHolder(itemView, listener) {
    override fun bindData(item: Cvodka) {
        super.bindData(item)
        val model = item as AchievementTestModel
        val image = if(model.medal.medal.image == null) model.medal.options.last().imageBig else model.medal.medal.image
        ImageUtils.loadAttachmentImage(context, image, itemView.equipmentImage)
    }
}

Интерфейс Cvodka будет по сути общим типом, список с ним мы будем передавать.

interface Cvodka {
    fun getType() : EnumCvodka
}

EnumCvodka нужен нам чтоб определить тип объекта

enum class EnumCvodka(val id: Int) {
HEADER(0, ACHIEVEMENT(1)

}

Сам AchievementTestModel может выглядеть так

class AchievementTestModel(var medal : AchievementModel) : Cvodka {
    override fun getType(): EnumCvodka {
        return EnumCvodka.ACHIEVEMENT
    }
}

В вашем фрагменте в onViewCreated

  val gridlayoutManager = GridLayoutManager(activity, MAX_SPAN_COUNT)
    gridlayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
        override fun getSpanSize(position: Int): Int {
            return when (adapter.getItemViewType(position)) {
                EnumCvodka.HEADER.id -> 12
                EnumCvodka.ACHIEVEMENT.id -> if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT)
                    resources.getInteger(R.integer.content_dostizenie_h) else resources.getInteger(R.integer.content_dostizenie_v)
                else -> 12
            }
        }
    }
    recyclerView.layoutManager = gridlayoutManager

Возможно у вас появился вопрос как создать List<Cvodka>

Это может быть что-то вроде такого

val lists = arrayListOf<Cvodka>()
lists.add(HeaderItemModelCvodka(achievementsTitles[0]))
for (medal in medalTwo) {
      lists.add(AchievementTestModel(medal))
}
READ ALSO
Не могу сделать перенос строки в string

Не могу сделать перенос строки в string

Если срабатывает if, то идет обращение к базе данных и от туда выводим столбец "team_name", записывается он в строковую переменную "resultat" и выводится...

123
FXML загрузчик не видит мой класс

FXML загрузчик не видит мой класс

Создал класс FanStackPane, который наследуется от обычного StackPane, для того что бы расставить элементы как я хочуНо теперь при старте программы вылетает...

121
Кодировка на Java

Кодировка на Java

Здравствуйте пишу простую программу на Java, но при компиляции в консоли выводит какие-то символы вроде этого "Р?Р?С?Р? Р?Р°С?РёР?Р° Р?С? Р?Р?Р?Р?С?Р?...

129