Визначення інтерфейсу у файлі XML. Файли Layout

Як правило, для визначення візуального інтерфейсу в проєктах під Android використовуються спеціальні файли XML. Ці файли є ресурсами розмітки та містять визначення візуального інтерфейсу у вигляді коду XML. Такий підхід нагадує створення веб-сайтів, де інтерфейс визначається у файлах HTML, а логіка додатку — в коді JavaScript.

Оголошення користувацького інтерфейсу в XML дозволяє відокремити інтерфейс додатку від коду. Це означає, що ми можемо змінювати визначення інтерфейсу без зміни Java-коду. Наприклад, можна створити XML-розмітки для різних орієнтацій екрана, розмірів пристроїв, мов тощо.

Файли розмітки графічного інтерфейсу розташовуються в проєкті в каталозі res/layout. За замовчуванням при створенні проєкту з порожньою activity вже є один файл ресурсів розмітки activity_main.xml, який може виглядати приблизно так:

res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
 
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

У файлі визначаються всі графічні елементи та їхні атрибути, які складають інтерфейс. При створенні розмітки в XML слід дотримуватися деяких правил: кожен файл розмітки повинен містити один кореневий елемент, який повинен представляти об'єкт View або ViewGroup.

У цьому випадку кореневим елементом є елемент ConstraintLayout, який містить елемент TextView.

Як правило, кореневий елемент містить визначення використовуваних просторів імен XML. Наприклад, у коді за замовчуванням у ConstraintLayout ми можемо побачити такі атрибути:

xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"

Кожен простір імен задається таким чином: xmlns:префікс="назва_ресурсу". Наприклад, у

xmlns:android="http://schemas.android.com/apk/res/android"

Назва ресурсу (або URI - Uniform Resource Indentifier) - "http://schemas.android.com/apk/res/android". І цей ресурс зіставляється з префіксом android (xmlns:android). Тобто через префікс ми зможемо посилатися на функціональність цього простору імен.

Кожен простір імен визначає деяку функціональність, яка використовується в застосунку, наприклад, надають теги та атрибути, які необхідні для побудови застосунку.

  • xmlns:android="http://schemas.android.com/apk/res/android": містить основні атрибути, які надаються платформою Android, застосовуються в елементах керування та визначають їхні візуальні властивості (наприклад, розмір, позиціонування). Наприклад, у коді ConstraintLayout використовується такий атрибут із простору імен "http://schemas.android.com/apk/res/android":
android:layout_width="match_parent"
  • xmlns:app="http://schemas.android.com/apk/res-auto": містить атрибути, що визначені в межах програми. Наприклад, у коді TextView:
app:layout_constraintBottom_toBottomOf="parent"
  • xmlns:tools="http://schemas.android.com/tools": застосовується для роботи з режимі дизайнера в Android Studio

Це найпоширеніші простори імен. І зазвичай кожен кореневий елемент (не обов'язково тільки ConstraintLayout) їх містить. Однак, якщо ви не плануєте користуватися графічним дизайнером в Android Studio і хочете працювати цілком у коді xml, то відповідно сенсу в просторі імен "http://schemas.android.com/tools" немає, і його можна прибрати.

Під час компіляції кожен XML-файл розмітки компілюється в ресурс View. Завантаження ресурсу розмітки здійснюється в методі Activity.onCreate. Щоб встановити розмітку для поточного об'єкта activity, треба в метод setContentView() як параметр передати посилання на ресурс розмітки.

setContentView(R.layout.activity_main);

Для отримання посилання на ресурс у коді java необхідно використовувати вираз R.layout.[назва_ресурсу]. Назва ресурсу layout збігатиметься з ім'ям файлу, тому щоб використовувати файл activity_main.xml як джерело візуального інтерфейсу, можна визначити наступний код у класі MainActivity:

MainActivity.java
package com.example.viewapp;
 
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
 
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
         
        // загрузка интерфейса из файла activity_main.xml
        setContentView(R.layout.activity_main);
    }
}

Додавання файлу layout

Але у нас може бути і кілька різних ресурсів layout. Як правило, кожен окремий клас Activity використовує свій файл layout. Або для одного класу Activity може використовуватися відразу кілька різних файлів layout.

Наприклад, додамо в проєкт новий файл розмітки інтерфейсу. Для цього натиснемо на папку res/layout правою кнопкою миші і в меню, що з'явилося, виберемо пункт New -> Layout Resource File: Додавання файлу layout в Android Studio

Після цього в спеціальному віконці буде запропоновано вказати ім'я і кореневий елемент для файлу layout: Встановлення параметрів для файлу layout в Android Studio

Як назву вкажемо second_layout. Усі інші налаштування залишимо за замовчуванням:

  • у полі Root element вказується кореневий елемент. За замовчуванням це androidx.constraintlayout.widget.ConstraintLayout.
  • поле Source set вказує, куди поміщати новий файл. За замовчуванням це main - область проєкту, з якою ми власне працюємо під час розроблення програми.
  • поле Directory main вказує папку в рамках каталогу, обраного в попередній опції, в який власне поміщається новий файл. За замовчуванням для файлів із розміткою інтерфейсу це layout.

Після цього в папку res/layout буде додано новий файл second_layout.xml, з яким ми можемо працювати так само, як і з activity_main.xml. Зокрема, відкриємо файл second_layout.xml і змінимо його вміст таким чином:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <TextView
        android:id="@+id/header"
        android:text="Welcome to Android"
        android:textSize="26sp"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

Тут визначено текстове поле TextView, яке має такі атрибути:

  • android:id - ідентифікатор елемента, через який ми зможемо посилатися на нього в коді. У записі android:id="@+id/header" символ @ вказує XML-парсеру використовувати решту рядка атрибута як ідентифікатор. А знак + означає, що якщо для елемента не визначено id зі значенням header, то його слід визначити.
  • android:text - текст елемента - на екран виводитиметься рядок "Welcome to Android".
  • android:textSize - висота шрифту (тут 26 одиниць)
  • android:layout_width - ширина елемента. Значення "match_parent" вказує, що елемент буде розтягуватися по всій ширині контейнера ConstraintLayout
  • android:layout_height - висота елемента. Значення "match_parent" вказує, що елемент буде розтягуватися по всій висоті контейнера ConstraintLayout

Застосуємо цей файл як визначення графічного інтерфейсу в класі MainActivity:

package com.example.viewapp;
 
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
 
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second_layout);
    }
}

Файл інтерфейсу називається second_layout.xml, тому за замовчуванням для нього створюватиметься ресурс R.layout.second_layout. Відповідно, щоб його використовувати, ми передаємо його до методу setContentView. У підсумку ми побачимо на екрані таке: Робота з layout в Android Studio

Отримання та управління візуальними елементами в коді

Вище визначений елемент TextView має один дуже важливий атрибут - id або ідентифікатор елемента. Цей ідентифікатор дає змогу звертатися до елемента, який визначено у файлі xml, з коду Java. Наприклад, перейдемо до класу MainActivity і змінимо його код:

package com.example.viewapp;
 
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
 
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // встановлюємо як інтерфейс файл second_layout.xml
        setContentView(R.layout.second_layout);
 
        // отримуємо елемент textView
        TextView textView = findViewById(R.id.header);
        // перевстановлюємо в нього текст
        textView.setText("Hello from Java!");
    }
}

За допомогою методу setContentView() встановлюється розмітка з файлу second_layout.xml.

Інший важливий момент, який варто відзначити - отримання візуального елемента TextView. Оскільки в його коді ми визначили атрибут android:id, то через цей id ми можемо його отримати.

Для отримання елементів за id клас Activity має метод findViewById(). У цей метод передається ідентифікатор ресурсу у вигляді R.id.[ідентифікатор_елемента]. Цей метод повертає об'єкт View - об'єкт базового класу для всіх елементів, тому результат методу ще необхідно привести до типу TextView.

Далі ми можемо щось зробити з цим елементом, у цьому разі змінюємо його текст.

Причому що важливо, отримання елемента відбувається після того, як у методі setContentView було встановлено розмітку, в якій цей візуальний елемент було визначено.

І якщо ми запустимо проект, то побачимо, що TextView виводить новий текст: Отримати елемент за допомогою findViewById в Android Studio