Это правильное решение для всех пицц, цитат, ощущений и прочих похожих элементов.
В ручную создавать каждый отдельный элемент такого списка это долго, муторно и в корне неправильно.
Такие списки предназначены для того чтобы отражать изменяющийся список каких либо товаров или услуг, а лезть с каждым изменением и перерисовать приложение слишком затратно. Тут то нам на поможет RecyclerView


<androidx.recyclerview.widget.RecyclerView
android:id="@+id/state_rec"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginStart="18dp"
android:layout_marginEnd="18dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/state_view"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/feel_rec"/>
Важно. Для правильного отображения следует задать layoutManager. LinearLayoutManager для стандартного списка, для таблицы с несколькими столбцами использует GridLayoutManager и свойство spanCount для количества этих самых столбцов. Свойство listitem нужно для визуального отображения элементов, дабы проверить правильность вёрстки.
Для простоты понимания, я надеюсь, я буду объяснять его работу на примере конструктора. RecyclerView — это эдакий робот, собирающий из данных ему деталей, по заданной схеме, нужные нам элементы. И для начала нам нужно понять, какие детали ему вообще нужны.

В этом случае данными будут являются текст снизу и картинка, т.к. они разные от элемента к элементу

Здесь данными являются название комнаты и картинка. Для создания dataclass нам нужно определять изменяющиеся данные, если что-либо повторяется от элемента к элементу, их проще задать сразу. В «перечне» данных они не нужны
Определив какие данные нам нужны нам нужно написать их «перечень» или, переходя к терминологии студии, DataClass
data class FeelData(val feel_title: String, val feel_ic : Int)
data class RoomData(val room_title: String, val room_ic : Int)
Определившись с перечнем создадим схему расположения этих деталей. Здесь важно именно само расположение, размеры и отступы. В знакомой вам рабочей тетради их обозвали адаптерами. но, на мой взгляд, лучше называть их представлениями.


Теперь приступим к написанию самого сборщика. Для примера возьмём собранный мной на скорую руку проект.
class RecyclerViewAdapter //Это сборщик вашего "конструктора"
(val context: Context, //Это входное поле, для условного "адреса сборки"
val list: ArrayList<RecyclerData> //Это поле куда вы подадите "детали" для сборки
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
сontext нужен для того чтобы наш адаптер понимал где ему нужно собирать эти данные, а list это собственно и есть список нужных данных-«деталей».
Для работы этого замечательного адаптера нужно четыре вещи:
class ViewHolder
Класс viewholder в наших аналогиях это описание схемы сборки. Название деталей и нахождение их на схеме сборки
class MyVH(itemview: View): RecyclerView.ViewHolder(itemview){
//Это описание мест для "деталей" в схеме
val text = itemview.findViewById<TextView>(R.id.textView)
val img = itemview.findViewById<ImageView>(R.id.img)
}
onCreateViewHolder
Это назначение для сборщика. Разбирая команду можно описать её следующим образом. По какому описанию, в каком месте и по какой схеме адаптер должен собирать элементы
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
//Эта запись показывает, куда, по какому описанию и по какой схеме собирать
return MyVH(LayoutInflater.from(context).inflate(R.layout.rec_view, parent,false))
}
onBindViewHolder
Вот здесь собственно и описывается сам процесс. В названое так место на схеме вставить вот эти данные.
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
//Это описание какие детали в какие сеста ставить
holder as MyVH //Эта строчка - уточнение по какому описанию происходит сборка
holder.text.text = list[position].text
holder.img.setImageResource(list[position].img)
}
holder as MyVH. Данная строчка, лишь уточнение, что сборка идёт по указанному описанию-Viewholder’у
getItemCount
Это метод возвращает количество собираемых элементов. Чаще всего оно соответствует количеству элементов в списке list, а его размер получается list.size
override fun getItemCount(): Int {
return list.size
//Метод возвращающий количество собираемых элементов
}
Остаётся последнее. Всё это дело подключить к нашему экрану. Для этого понадобится всего ничего
//Сами "детали" для сборки
val list: ArrayList<RecyclerData> = arrayListOf(
RecyclerData("1 Cherry",R.drawable.cherry_ic),
RecyclerData("2 Cherry",R.drawable.cherry_ic),
RecyclerData("3 Cherry",R.drawable.cherry_ic),
RecyclerData("4 Cherry",R.drawable.cherry_ic),
RecyclerData("5 Cherry",R.drawable.cherry_ic),
)
//Переменная для представления сборщика
val rec: RecyclerView = findViewById(R.id.recycler)
//Подключениe RecyclerView, с передачей места сборки(this = здесь) и "деталей"
rec.adapter = RecyclerViewAdapter(this, list)
Переменная с указанием ID RecyclerView. Список «деталей» по заданному DataClass’у, вызов метода присваивания адаптера для отображению и вуоля! Вы потрясающи!
