Существует несколько подходов:
Использование нескольких ViewTypes в адаптере. Самый распространенный и гибкий способ. Адаптер переопределяет метод getItemViewType, который возвращает тип представления для конкретной позиции. Затем в методах onCreateViewHolder и onBindViewHolder используется этот тип для создания и привязки соответствующего ViewHolder.
kotlin
Использование библиотек. Существуют библиотеки, упрощающие работу с множественными ViewTypes, например, Groupie или Epoxy. Они предоставляют абстракции для определения "items" с соответствующими ViewHolders и логикой привязки.
Groupie:
kotlin
Epoxy: Использует аннотации для генерации EpoxyModel и EpoxyController.
Использование составных ViewHolders. Менее распространенный подход, когда один ViewHolder содержит несколько различных представлений и выбор видимого представления производится внутри ViewHolder (через setVisibility или другими способами). Не рекомендуется для большого количества разных типов или сложной логики.
Разделение данных. Если данные можно четко разделить на группы с разными представлениями, можно использовать несколько независимых RecyclerViews (что часто неоптимально) или композицию адаптеров.