Sobes.tech
Middle

Jak vyřešit problém s různými typy zobrazení pro RecyclerView?

sobes.tech AI

Odpověď od AI

Existuje několik přístupů:

  1. Použití více ViewTypes v adapteru. To je nejběžnější a nejflexibilnější způsob. Adapter přepíše metodu getItemViewType, která vrací typ zobrazení pro konkrétní pozici. Tento typ se pak používá v metodách onCreateViewHolder a onBindViewHolder k vytvoření a přiřazení odpovídajícího ViewHolder.

    class MyAdapter(private val items: List<Item>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    
        private val VIEW_TYPE_TEXT = 0
        private val VIEW_TYPE_IMAGE = 1
    
        override fun getItemViewType(position: Int): Int {
            return when (items[position]) {
                is TextItem -> VIEW_TYPE_TEXT
                is ImageItem -> VIEW_TYPE_IMAGE
            }
        }
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
            return when (viewType) {
                VIEW_TYPE_TEXT -> {
                    val view = LayoutInflater.from(parent.context).inflate(R.layout.item_text, parent, false)
                    TextViewHolder(view)
                }
                VIEW_TYPE_IMAGE -> {
                    val view = LayoutInflater.from(parent.context).inflate(R.layout.item_image, parent, false)
                    ImageViewHolder(view)
                }
                else -> throw IllegalArgumentException("Neplatný typ zobrazení")
            }
        }
    
        override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
            when (holder.itemViewType) {
                VIEW_TYPE_TEXT -> {
                    val textHolder = holder as TextViewHolder
                    val textItem = items[position] as TextItem
                    textHolder.bind(textItem)
                }
                VIEW_TYPE_IMAGE -> {
                    val imageHolder = holder as ImageViewHolder
                    val imageItem = items[position] as ImageItem
                    imageHolder.bind(imageItem)
                }
            }
        }
    
        override fun getItemCount(): Int {
            return items.size
        }
    
        // ViewHolders pro různé typy
        class TextViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
            private val textView: TextView = itemView.findViewById(R.id.textView)
            fun bind(item: TextItem) {
                textView.text = item.text
            }
        }
    
        class ImageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
            private val imageView: ImageView = itemView.findViewById(R.id.imageView)
            fun bind(item: ImageItem) {
                // Načtení obrázku
            }
        }
    }
    
    data class TextItem(val text: String)
    data class ImageItem(val imageUrl: String)
    
  2. Použití knihoven. Existují knihovny, které usnadňují práci s více ViewTypes, například Groupie nebo Epoxy. Poskytují abstrakce pro definování "items" s odpovídajícími ViewHolders a logikou vazby.

    • Groupie:

      class MyItemAdapter(private val items: List<GroupieItem<*>>) : GroupAdapter<ViewHolder>() {
          init {
              addAll(items)
          }
      }
      
      // Příklad Groupie item
      class TextItemGroupie(private val text: String) : Item<ViewHolder>() {
          override fun getLayout(): Int = R.layout.item_text
      
          override fun bind(viewHolder: ViewHolder, position: Int) {
              viewHolder.itemView.findViewById<TextView>(R.id.textView).text = text
          }
      }
      
      class ImageItemGroupie(private val imageUrl: String) : Item<ViewHolder>() {
          override fun getLayout(): Int = R.layout.item_image
      
          override fun bind(viewHolder: ViewHolder, position: Int) {
             // Načtení obrázku
          }
      }
      
    • Epoxy: Používá anotace k generování EpoxyModel a EpoxyController.

  3. Použití složených ViewHolders. Méně běžný přístup, kdy jeden ViewHolder obsahuje několik různých zobrazení a výběr viditelného zobrazení se provádí uvnitř ViewHolder (například přes setVisibility nebo jiné způsoby). Nedoporučuje se pro velké množství různých typů nebo složitou logiku.

  4. Rozdělení dat. Pokud lze data jasně rozdělit do skupin s různými zobrazeními, lze použít několik nezávislých RecyclerView (což není vždy optimální) nebo kompozici adaptérů.