# 4. Работа ViewGroup
Снова про `root` класс для всех виджетов.
# View
Android SDK включает множество виджетов, которые являются дочерним классом класса `View`. Таким образом, каждый виджет является экземпляром класса `View`, как и отражено на рисунке ниже.

Рис. 1. Иерархия класса `View`. [Источник изображения](https://www.mathematik.uni-marburg.de/~thormae/lectures/graphics1/media/vectorart/android_class_hierarchy_view.svg).
# ViewGroup
Макет определяет структуру пользовательского интерфейса в вашем приложении, например в [действии](https://developer.android.com/guide/components/activities?hl=ru) . Все элементы макета построены с использованием иерархии объектов [View](https://developer.android.com/reference/android/view/View?hl=ru) и [ViewGroup](https://developer.android.com/reference/android/view/ViewGroup?hl=ru) . `View` обычно рисует то, что пользователь может видеть и с чем может взаимодействовать. `ViewGroup` — это невидимый контейнер, определяющий структуру макета для `View` и других объектов `ViewGroup` , как показано на рисунке 1.

**Рисунок 1.** Иллюстрация иерархии представлений, определяющей макет пользовательского интерфейса.
Объекты `View` часто называются **_виджетами_** и могут быть одним из многих подклассов, таких как [Button](https://developer.android.com/reference/android/widget/Button?hl=ru) или [TextView](https://developer.android.com/reference/android/widget/TextView?hl=ru) . Объекты `ViewGroup` обычно называются **_макетами_** и могут относиться к одному из многих типов, предоставляющих другую структуру макета, например [LinearLayout](https://developer.android.com/reference/android/widget/LinearLayout?hl=ru) или [`ConstraintLayout`](https://developer.android.com/reference/androidx/constraintlayout/widget/ConstraintLayout?hl=ru) .
Объявить макет можно двумя способами:
- **Объявляйте элементы пользовательского интерфейса в XML.** Android предоставляет простой словарь XML, соответствующий классам и подклассам `View` , например, для виджетов и макетов. Вы также можете использовать [редактор макетов](https://developer.android.com/studio/write/layout-editor?hl=ru) Android Studio для создания макета XML с помощью интерфейса перетаскивания.
- **Создание экземпляров элементов макета во время выполнения.** Ваше приложение может создавать объекты `View` и `ViewGroup` и программно управлять их свойствами.
**Совет:** Для отладки макета во время выполнения используйте инструмент [«Инспектор макета»](https://developer.android.com/studio/debug/layout-inspector?hl=ru) .
## XML
Используя словарь XML Android, вы можете быстро разрабатывать макеты пользовательского интерфейса и элементы экрана, которые они содержат, точно так же, как вы создаете веб-страницы в HTML с рядом вложенных элементов.
Каждый файл макета должен содержать ровно один корневой элемент, который должен быть объектом `View` или `ViewGroup` . После определения корневого элемента вы можете добавить дополнительные объекты или виджеты макета в качестве дочерних элементов, чтобы постепенно построить иерархию `View` , определяющую ваш макет. Например, вот макет XML, в котором используется вертикальный `LinearLayout` для хранения `TextView` и `Button` :
```xml
```
После объявления макета в XML сохраните файл с расширением `.xml` в каталоге `res/layout/` вашего проекта Android, чтобы он правильно скомпилировался.
Дополнительные сведения о синтаксисе XML-файла макета см. в [разделе layout-resource](https://developer.android.com/guide/topics/resources/layout-resource?hl=ru) .
## Подключение XML-res
При компиляции приложения каждый файл макета XML компилируется в ресурс `View` . Загрузите ресурс макета в реализацию обратного вызова [Activity.onCreate()](https://developer.android.com/reference/android/app/Activity?hl=ru#onCreate(android.os.Bundle)) вашего приложения. Сделайте это, вызвав [setContentView()](https://developer.android.com/reference/android/app/Activity?hl=ru#setContentView(int)) , передав ему ссылку на ваш ресурс макета в форме: `R.layout. _layout_file_name_` . Например, если ваш XML-макет сохранен как `main_layout.xml` , загрузите его для своей `Activity` следующим образом:
```Kotlin
fun onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_layout)
}
```
Платформа Android вызывает метод обратного вызова `onCreate()` в вашем `Activity` при запуске `Activity` . Дополнительные сведения о жизненных циклах действий см. в [разделе Введение в действия](https://developer.android.com/guide/components/activities?hl=ru#Lifecycle) .
## Атрибуты
Каждый объект `View` и `ViewGroup` поддерживает собственный набор атрибутов XML. Некоторые атрибуты специфичны для объекта `View` . Например, `TextView` поддерживает атрибут `textSize` . Однако эти атрибуты также наследуются любыми объектами `View` , расширяющими этот класс. Некоторые из них являются общими для всех объектов `View` , поскольку они наследуются от корневого класса `View` , например атрибут `id` . Другие атрибуты считаются _параметрами макета_ , которые являются атрибутами, описывающими определенные ориентации макета объекта `View` , как определено родительским объектом `ViewGroup` этого объекта.
### ИДЕНТИФИКАТОР
Любой объект `View` может иметь связанный с ним целочисленный идентификатор, позволяющий однозначно идентифицировать `View` в дереве. При компиляции приложения этот идентификатор упоминается как целое число, но идентификатор обычно назначается в XML-файле макета в виде строки в атрибуте `id` . Это атрибут XML, общий для всех объектов `View` , и он определяется классом `View` . Вы используете его очень часто. Синтаксис идентификатора внутри тега XML следующий:
```xml
android:id="@+id/my\_button"
```
_Символ_ (@) в начале строки указывает, что синтаксический анализатор XML анализирует и расширяет остальную часть строки идентификатора и идентифицирует ее как ресурс идентификатора. Символ _плюса_ (`+`) означает, что это новое имя ресурса, которое необходимо создать и добавить к вашим ресурсам в файле `R.java` .
Платформа Android предлагает множество других ресурсов для идентификации. При ссылке на идентификатор ресурса Android вам не нужен символ _плюса_ , но вы должны добавить пространство имен пакета `android` следующим образом:
```xml
android:id="@android:id/empty"
```
Пространство имен пакета `android` указывает, что вы ссылаетесь на идентификатор из класса ресурсов `android.R` , а не из класса локальных ресурсов.
Чтобы создавать `View` и ссылаться на них из вашего приложения, вы можете использовать следующий общий шаблон:
1. Определите представление в файле макета и присвойте ему уникальный идентификатор, как в следующем примере:
```xml
```
2. Создайте экземпляр объекта представления и запишите его из макета, обычно с помощью метода [onCreate()](https://developer.android.com/reference/android/app/Activity?hl=ru#onCreate(android.os.Bundle)) , как показано в следующем примере:
```Kotlin
val myButton: Button = findViewById(R.id.my_button)
```
Определение идентификаторов для объектов представления важно при создании [RelativeLayout](https://developer.android.com/reference/android/widget/RelativeLayout?hl=ru) . В относительном макете родственные представления могут определять свой макет относительно другого родственного представления, на которое ссылается уникальный идентификатор.
Идентификатор не обязательно должен быть уникальным во всем дереве, но он должен быть уникальным в той части дерева, в которой вы ищете. Часто это может быть все дерево, поэтому лучше сделать его уникальным, если это возможно.
### Параметры макета
Атрибуты макета XML с именем `layout_ _something_` определяют параметры макета для `View` , соответствующие `ViewGroup` , в которой оно находится.
Каждый класс `ViewGroup` реализует вложенный класс, расширяющий [ViewGroup.LayoutParams](https://developer.android.com/reference/android/view/ViewGroup.LayoutParams?hl=ru) . Этот подкласс содержит типы свойств, которые определяют размер и положение каждого дочернего `View` в зависимости от `ViewGroup`. Как показано на рисунке 2, родительская `ViewGroup`й определяет параметры макета для каждого дочернего `View`, включая дочернюю `ViewGroup`.

**Рисунок 2.** Визуализация иерархии `View` с параметрами макета, связанными с каждым `View`.
Каждый подкласс `LayoutParams` имеет свой собственный синтаксис для установки значений. Каждый дочерний элемент должен определять `LayoutParams` , соответствующий его родительскому элементу, хотя он также может определять разные `LayoutParams` для своих собственных дочерних элементов.
Вы можете указать ширину и высоту с точными измерениями, но, возможно, вам не захочется делать это часто. Чаще всего вы используете одну из этих констант для установки ширины или высоты:
- `wrap_content` : сообщает вашему `View`, что его размер соответствует размерам, требуемым его содержимым.
- `match_parent` : сообщает вашему `View`, что оно должно стать настолько большим, насколько позволяет его родительская `ViewGroup`.
Как правило, мы не рекомендуем указывать ширину и высоту макета в абсолютных единицах, таких как пиксели. Лучшим подходом является использование относительных измерений, таких как независимые от плотности пиксельные единицы (dp), `wrap_content` или `match_parent` , поскольку это помогает вашему приложению правильно отображаться на экранах различных размеров. Принятые типы измерений определены в [ресурсе макета](https://developer.android.com/guide/topics/resources/layout-resource?hl=ru) .
## Положение макета
`View` имеет прямоугольную геометрию. Он имеет местоположение, выраженное как пара **_левой_** и **_верхней_** координат, и два измерения, выраженные как ширина и высота. Единицей местоположения и размеров является пиксель.
Вы можете получить местоположение представления, вызвав методы [getLeft()](https://developer.android.com/reference/android/view/View?hl=ru#getLeft()) и [getTop()](https://developer.android.com/reference/android/view/View?hl=ru#getTop()) . Первый возвращает левую координату ( _x_ ) прямоугольника, представляющего `View`. Последний возвращает верхнюю координату ( _y_ ) прямоугольника, представляющего `View`. Эти методы возвращают расположение `View` относительно его родителя. Например, когда `getLeft()` возвращает 20, это означает, что представление расположено на 20 пикселей правее левого края его прямого родительского элемента.
Кроме того, существуют удобные методы, позволяющие избежать ненужных вычислений: а именно [getRight()](https://developer.android.com/reference/android/view/View?hl=ru#getRight()) и [getBottom()](https://developer.android.com/reference/android/view/View?hl=ru#getBottom()). Эти методы возвращают координаты правого и нижнего краев прямоугольника, представляющего `View`. Например, вызов `getRight()` аналогичен следующему вычислению: `getLeft() + getWidth()` .