Sobes.tech
Middle

Como resolver o problema com diferentes tipos de visualizações para RecyclerView?

sobes.tech IA

Resposta da IA

Existem várias abordagens:

  1. Utilização de múltiplos ViewTypes no adaptador. A forma mais comum e flexível. O adaptador sobrescreve o método getItemViewType, que devolve o tipo de vista para uma posição específica. Depois, nos métodos onCreateViewHolder e onBindViewHolder, esse tipo é usado para criar e ligar o ViewHolder correspondente.

    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 para diferentes tipos
        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) {
                // Cargar imagen
            }
        }
    }
    
    data class TextItem(val text: String)
    data class ImageItem(val imageUrl: String)
    
  2. Utilização de bibliotecas. Existem bibliotecas que facilitam o trabalho com múltiplos ViewTypes, como Groupie ou Epoxy. Elas fornecem abstrações para definir "items" com seus respectivos ViewHolders e lógica de ligação.

    • Groupie:

      class MyItemAdapter(private val items: List<GroupieItem<*>>) : GroupAdapter<ViewHolder>() {
          init {
              addAll(items)
          }
      }
      
      // Exemplo de 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) {
             // Carregar imagem
          }
      }
      
    • Epoxy: Usa anotações para gerar EpoxyModel e EpoxyController.

  3. Utilização de ViewHolders compostos. Abordagem menos comum, onde um ViewHolder contém várias vistas diferentes e a seleção da vista visível é feita dentro do ViewHolder (através de setVisibility ou outros métodos). Não recomendada para um grande número de tipos diferentes ou lógica complexa.

  4. Separação de dados. Se os dados podem ser claramente divididos em grupos com diferentes vistas, pode-se usar vários RecyclerViews independentes (o que muitas vezes não é ótimo) ou composição de adaptadores.