Sobes.tech
Middle

Comment résoudre le problème avec différents types de vues pour RecyclerView?

sobes.tech IA

Réponse de l'IA

Il existe plusieurs approches :

  1. Utilisation de plusieurs ViewTypes dans l'adaptateur. La méthode la plus courante et flexible. L'adaptateur surcharge la méthode getItemViewType, qui retourne le type de vue pour une position spécifique. Ensuite, dans les méthodes onCreateViewHolder et onBindViewHolder, ce type est utilisé pour créer et lier le ViewHolder correspondant.

    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("Invalid view type")
            }
        }
    
        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 pour différents types
        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) {
                // Charger l'image
            }
        }
    }
    
    data class TextItem(val text: String)
    data class ImageItem(val imageUrl: String)
    
  2. Utilisation de bibliothèques. Il existe des bibliothèques qui simplifient le travail avec plusieurs ViewTypes, comme Groupie ou Epoxy. Elles fournissent des abstractions pour définir des "items" avec leurs ViewHolders respectifs et leur logique de liaison.

    • Groupie :

      class MyItemAdapter(private val items: List<GroupieItem<*>>) : GroupAdapter<ViewHolder>() {
          init {
              addAll(items)
          }
      }
      
      // Exemple d'item Groupie
      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) {
             // Charger l'image
          }
      }
      
    • Epoxy : Utilise des annotations pour générer EpoxyModel et EpoxyController.

  3. Utilisation de ViewHolders composés. Approche moins courante, où un ViewHolder contient plusieurs vues différentes et la sélection de la vue visible est effectuée à l'intérieur du ViewHolder (via setVisibility ou d'autres méthodes). Non recommandée pour un grand nombre de types différents ou une logique complexe.

  4. Séparation des données. Si les données peuvent être clairement divisées en groupes avec des vues différentes, on peut utiliser plusieurs RecyclerViews indépendants (ce qui n'est souvent pas optimal) ou une composition d'adaptateurs.