Урок 2: Введение в XML, что такое View, теги и атрибуты

Итак мы планомерно вливаемся в разработку Android-приложений. Начинаем подготовку к верстке своего первого экрана для нашего учебного приложения для изучения английских слов. У меня в Figma есть дизайн-макет с несколькими экранами, так что представим, что это наш заказ на разработку или задачка с нового места работы. Только делать его будем не торопясь, соблюдая на начальных уроках некоторые педагогические упрощения. Ссылка на макет.

Окей. После создания нового проекта Android Studio сгенерировала для нас ряд файлов. Мы будем детально разбираться подробнее с каждым из них, но постепенно. И сейчас нас интересует основной файл, в котором пока будем писать код – MainActivity.kt.

MainActivity.kt. файл в котором пишется код

Что такое файл MainActivity.kt?

Activity в целом – является одним из базовых системных компонентов Android. Пока достаточно понимать, что Activity представляет собой окно или страницу приложения. То, что видит пользователь и с чем он может взаимодействовать в настоящий момент.

MainActivity – по сути обычный класс, который наследуется от AppCompatActivity (который в свою очередь является базовым классом Activity и предоставляет различные возможности для разработки Android). Помните, на курсе по Kotlin мы создавали экземпляры классов? Экземпляр MainActivity не создается руками, а генерируется системой автоматически. То есть — разработчик не вызывает конструктор класса. Нам достаточно было прописать его в AndroidManifest.xml, чтобы система его увидела и использовала то, что мы будем прописывать внутри этого класса.

Манифест – это конфигурационный файл приложения, все Activity нужно указывать тут, но об этом позже.

onCreate()

Вернемся. В классе мы видим переопределенный метод onCreate() – метод является частью жизненного цикла Activity. Этот цикл содержит ряд методов, которые вызываются в разных состояниях приложения. Например, когда приложение стартует, сворачивается, уничтожается и так далее.

Сейчас только достаточно знать, что внутри onCreate() мы описываем то, что происходит в момент создания экрана. Перед тем, как его содержимое увидит пользователь. То есть где-то внутри система создает нам экземпляр MainActivity, а дальше вызывает метод жизненного цикла onCreate().

Внутри при помощи ключевого слова super вызывается onCreate() родителя, в параметры которого отправляются данные о сохраненном состоянии экрана. И, что наиболее интересно сейчас, нам, как разработчикам, необходимо вызвать setContentView().

setContentView()

Дословно setContentView() можно перевести как “установить контент отображения”. Метод используется для установки UI макета для конкретной Activity. То есть мы передаем в него XML макет, в котором размещена непосредственно верстка видимого экрана. По сути можно сказать, что в этом месте мы связываем файл макета с файлом конкретного экрана – в нашем случае activity_main.xml c MainActivity.kt.

Обратите внимание на сигнатуру метода – он принимает целое число Int. Это значит, что мы передаем “айдишник” файла макета activity_main. ID макета, на который мы ссылаемся через R.layout, генерируется автоматически, мы передаем его в метод в качестве параметра. Рассмотрим подробнее activity_main.xml .

Файл XML разметки activity_main.xml

Для начала пора бы уже запустить наше приложение на эмуляторе. Видим пустой экран со стандартной надписью “Hello World”.

Запуск приложения на эмуляторе

Хорошо. Переходим в файл разметки.

Существуют разные виды представления в Android Studio. По-умолчанию открывается Design. Мы видим предпросмотр макета и его схематичное представление.

Предпросмотр макета в Android Studio

Кнопка Code оставляет только код. А Split разделяет экран и показывает и код, и предпросмотр макета. Дополнительно в настройках уберу схематичное отображение и теперь с разметкой можно работать.

Код и предпросмотр макета

Итак, здесь мы видим некоторый текст. По факту это такой формат хранения данных – XML. Он довольно древний, но простой и универсальный.

Интерфейс Android приложения – это иерархия различных View. View – это по сути элементы на экране, которые могут состоять их текста, кнопок, контейнеров, списков и так далее. Эти “вьюхи” можно выстраивать в иерархии, чтобы создавать интерфейс пользователя различной сложности. Также еще можно сказать, что View – это технически тоже класс, который представляет собой отрисовываемую на экране часть интерфейса.

View класс

В XML разметке каждый элемент “вью” представляется с помощью тегов. Теги используются для определения начала и конца элемента, а также для указания его свойств и содержимого.

Например, чтобы разместить какой-нибудь текст на экране используется тэг <TextView>. Обратите внимание, что сначала открывается тег, пишется название, затем перечисляются его атрибуты (или настройки). В конце тэг закрывается символом обратного слэша. Внутри открывающего тега можно указывать атрибуты элемента, такие как размеры, цвета и другие свойства.

<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

Также будет валидной запись, если использовать два тега: открывающий и закрывающий. Например, вот так.

<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
</TextView>

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

Чтобы было проще ориентироваться при клике на названия тегов они подсвечиваются в коде и в превью экрана.

Для демонстрации давайте изменим текст в TextView и перезапустим приложение. Новый билд собрался и установился на эмулятор – наш текст корректно отображается.

Разбор имеющихся тегов activity_main.xml

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

<androidx.constraintlayout.widget.ConstraintLayout>: Это открывающий тег для элемента ConstraintLayout, который является контейнером для размещения других элементов с использованием ограничений (constraints). Что это значит будем рассматривать подробнее далее. А еще обратите внимание, полное имя компонента с пакетом указывается для библиотечных UI-компонентов (или самописных). Короткое название подставляется для встроенных в SDK компонентов.

xmlns

Атрибуты xmlns – это аббревиатура от «XML Namespace”. Техническая информация, которая определяет и связывает префиксы с конкретными пространствами имен. То есть, обозначив нужные инструкции, теперь можно в документе использовать определенный набор атрибутов (с соответствующими префиксами). Вот какие префиксы тут перечислены:

  • android – это, собственно, атрибуты, которые система Android распознает для этих view, она будет из них читать параметры и использовать.
  • app – это специальное пространство имен для того, чтобы добавлять атрибуты, которые расширяют стандартное поведение андроида.
  • tools – используется для того, чтобы переопределять какие-то атрибуты, которые нам нужны только во время разработки. То есть пользователь не увидит эти изменения.

layout_width и layout_height

Далее. layout_width и layout_height: Это атрибуты, которые отвечают за ширину и высоту элемента. Могут принимать несколько значений. Например:

  • match_parent – означает, что элемент будет занимать всю доступную ширину родительского контейнера. То есть если мы проставим это значение у текстового элемента, то увидим на превью, что элемент TextView занял всю ширину экрана. То есть ему передалось значение родительского тэга — тоже match_parent.
  • wrap_content – означает, что элемент будет автоматически подстроен под размер содержимого (ширину или высоту).
  • ширину и высоту можно задать конкретными числовыми значениями. Например, установим значение в 150dp и увидим изменения размера области TextView на превью.
Ширина и высота элемента TextView

dp – density-independent pixel

dp используется в качестве единицы измерения расстояний для элементов. dp это сокращение от density-independent pixel – пиксель не привязанный к плотности экрана. Дело в том, что устройства имеют разную плотность пикселей. То есть разное количество пикселей на дюйм. Использование этой единицы измерения гарантирует, что размер будет автоматически масштабироваться. Что обеспечит одинаковые пропорции элементов для сохранения лаконичного внешнего вида на разных устройствах.

TextView внутри ConstraintLayout

Чтож. Добавим еще один текстовый элемент. Ширина и высота будут по размеру контента. Закрываем тэг и видим подсвечиваемую ошибку. This view is not constrained. Нужно запомнить, что если мы располагаем элемент внутри контейнера ConstraintLayout, ему обязательно надо проставлять ограничители. Если сказать проще, то его обязательно нужно куда-нибудь приклеить минимум по 2 сторонам из четырех.

Если нажмем на элемент появятся такие точки за которые можно тянуть и приклеивать к другим элементам. Допустим, мы хотим разместить новый текст под уже имеющимся. Значит мне нужно потянуть за его верхнюю грань и прилепить к нижней грани другого элемента.

Размещение элемента внутри контейнера ConstraintLayout

Отлично, мы добавили правило и теперь нижний текст расположен под верхним. Пока мы добавили только отношение по вертикали. По горизонтали положение элемента осталось без изменений. Давайте обратим внимание на изменения в коде.

  • Во-первых у первого текста появился новый атрибут id – android:id="@+id/textView”. Он сгенерировался автоматически, потому что нашему элементу надо понимать к чему цепляться. Такие “айдишники” мы будем прописывать в будущем самостоятельно для обращения к ним из класса MainActivity. Чтобы как-то с ними взаимодействовать.
  • Во-вторых в нижнем элементе появился атрибут отношения к вышеописанному элементу. А именно тут написано, что сторона Top относится к стороне Bottom элемента с id textView. То есть верх нашего элемента к низу другого элемента. Такие атрибуты будут прописаны ко всем сторонам в зависимости от того, откуда и куда мы будем их клеить.

Отлично, наш тэг по прежнему подсвечивается красным, потому, что нужно минимум два “констрейнта”. Потянем правую грань до правой части экрана. Появилось значение атрибута parent. Что означает, что элемент будет привязан к краю родительского элемента. Ошибка пропала и это значит, что можно запустить приложение и убедиться, что все отображается также, как и в превью.

Окей. Контейнер ConstraintLayout крут своей гибкостью. Например, если привязать элемент между другими элементами, то он по умолчанию займет положение по середине. И всегда будет адаптивно центрироваться вне зависимости от экранов устройств. Притянем остальные грани до граней контейнера и убедимся, что элемент повис ровно по середине заданных рамок.

Раз уж мы задержались на TextView, на его примере давайте рассмотрим еще пару атрибутов по изменению текста.

  • Если мы хотим разместить содержимое контейнера по середине, то можно использовать android:gravity=»center”. Причем значение атрибута центрирует сразу по вертикали и по горизонтали. Для центровки по отдельности есть android:gravity=»center_horizontal” и vertical соответственно. Есть еще атрибут layout_gravity — об их отличиях поговорим на следующем уроке.
  • Для изменения размера текста используется атрибут textSize. Увеличим текст до 20. android:textSize="20sp". Как видите, для значений размера шрифта используется другая адаптивная единица измерения – sp (scalable pixel или в переводе на русский — масштабируемый).
  • Чтобы задать цвет текста используем textColor. Я не помню на память какой-нибудь код цвета, отличный от черного или белого, поэтому сделаем так. Введем черный и выберем любой интересующий через палитру. android:textColor="#7A03AC"
  • Значения атрибутов могут также принимать Boolean значения. Например, есть такой android:textAllCaps="true". Весь текст теперь написан капсом.
textAllCaps для написания капсом

Документация внутри Android Studio

Тут может возникнуть ужас от осознания необходимости держать в голове кучу атрибутов для каждого типа View. Без Паники. Вот пара приемов которая вам поможет.

Первый — как найти документацию, наведите курсов на имя View и задержитесь на несколько секунд или нажмите F1 (cntrl + Q на Windows), когда курсор находится на названии View. Появится быстрая справка, на которой можно найти простой пример использования.

Справка по атрибутам View

При повторном нажатии F1 (cntrl + Q на Windows) откроется вкладка Документация.

Документация по атрибутам View

Теперь кликая по тегам мы видим документацию для них. Вся остальная и наиболее актуальная документация находится на официальном сайте developer.android.com. На всякий случай ссылка под видео.

Создание нового layout

Наконец хочу еще продемонстровать привязку макета к Activity чуть более наглядно. Как вы понимаете, мы можем передавать для отрисовки в setContentView() и другие файлы разметки. Находясь в XML сначала нажмем на прицел и откроем местоположение файла в проекте. Он лежит в главной папке с ресурсами res, в подпапке с лейаутами layout. Все как и описывалось ранее, советую запомнить эту кнопку — я бы ее назвал “Где Я”.

Кликнув правой кнопкой по папке layout, создадим новый файл. Файл можно создавать с полного нуля, но лучше воспользоваться пунктом контекстного меню New → Layout Resource File. При наименовании принято сперва указывать тип разметки или назначение, затем через нижнее подчеркивание уникальное название.

Создадим по аналогии activity_second.xml, подразумевая, что этот лейаут мы тоже будем использовать для Activity. Расширение xml можно не указывать. В пункте “Root Element” указывается какой будет основной контейнер для этого макета, по-умолчанию это ConstraintLayout. Что меня полностью устраивает.

Создание activity_second

Файл корректно создался в папке с остальными лейаутами.

Добавление кнопки – тэг Button

Добавим на него какой-нибудь элемент. Пусть это будет кнопка. Открываем тэг и начинаем вводить Button.

Создание кнопки

Android Studio умная — она проиндексировала стандартные и сторонние библиотеки, включенные в проект, и теперь предлагает различные варианты.

  • Button – (который нам нужен) является базовым классом из стандартной библиотеки Android android.widget.Button. Он предоставляет основные возможности для создания кнопок в Android приложении.

Кроме того можно видеть другие варианты кнопок, например, ImageButton (кнопка с изображением), различные кнопки-переключатели типа RadioButton и ToggleButton. Это все принципиально другие компоненты со своей функциональностью. Ими мы будем пользоваться при верстке экранов в будущем.

Button и AppCompatButton

Однако, если взять AppCompatButton — это будет тоже обычная кнопка. Но она располагается в библиотеке поддержки AppCompat. Я сейчас не буду в это погружаться, но в двух словах — эта библотека существует, чтобы UI-компоненты корректно работали на старых устройствах. И самое главное — под капотом система сама при необходимости обращается к этой поддержке и нам не надо специально использовать кнопки и другие элементы из библиотеки AppCompat. Поэтому мы выбираем обычный Button, встроенный в SDK.

Библиотеки в проекте

Я упоминаю слово “библиотеки”. Что это за библиотеки вообще такие. Помните при создании проекта мы выбирали SDK. Вот этот development kit хранит в себе определенное количество стандартных библиотек с различными вспомогательными классами, в том числе и для “вьюшек”.

Убедиться в этом можно переключившись в режим Project вкладки Project, провалившись в декларацию классов для тэга Button и нажав на прицел в иерархии файлов. Это и есть список стандартных библиотек и Button как я и сказал находится в стандартном SDK.

Button находится в стандартном SDK

Теперь давайте как то центрируем кнопки на экране с помощью “констрейнтов”. Добавим отступы для верхних граней. margin добавляет отступ для внешней границы элемента, о них тоже поговорим подробнее в следующем уроке. Чтобы задать кнопке текст добавляем атрибут text. И как-то мелковато. Изменим размер, задав конкретную ширину и высоту.

Центрирование кнопок с помощью “констрейнтов”.

Привязка нового layout к Activity

Окей. Теперь я хочу, чтобы этот файл с макетом подтягивался в экран MainActivity вместо текущего файла макета activity_main. Для этого просто в setContentView() я передаю “айди” этого файла разметки. Теперь приложение можно запустить и увидим наш созданный макет.

Передача файла с макетом в экран MainActivity

Мы не приступили к верстке экрана самого приложения, однако, качественная подготовка почвы очень важный педагогический элемент. Чтобы не упустить важных деталей и не перегружаться информацией.

Если что-то сразу непонятно — не переживайте, постепенно все темы будем раскрывать подробнее.

Для тех, кто собрался стать Android-разработчиком

Пошаговаясхема
Пошаговая
схема

Описание процесса обучения от основ Kotlin до Android-разработчика

Бесплатныеуроки
Бесплатные
уроки

Авторский бесплатный курс по основам языка программирования Kotlin

Обучающийбот
Обучающий
бот

Тренажер и самоучитель по Котлин – бесплатные тесты и практика

Поделиться уроком

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *