Разработка под Android требует умения создавать интерфейсы, которые будут симпатичны и просты в использовании. Удобство использования часто называют user-friendly.
Для создания визуальной части приложения в Android-разработке используются XML-файлы разметки. После этого элементами интерфейса можно управлять из Java-кода. В этой статье мы подробно рассмотрим, как это делается.
Связь Java-класса Activity и XML-layout
XML-файлы разметки – это способ определения структуры интерфейса приложения. Они содержат описания элементов пользовательского интерфейса, таких как кнопки, текстовые поля, изображения и другие. В таких файлах вся информация описывается при помощи тегов, заключённых в треугольные скобки.
Если заглянуть в XML-файл activity_main.xml, заботливо сгенерированный IntelliJ IDEA для MainActivity.java, там обнаружится компонент-контейнер ConstraintLayout. В нём пока ничего нет. Впоследствии в этот контейнер можно будет добавить разные компоненты.
ConstraintLayout – это один из видов Layout, рассказывающих приложению, как именно нужно располагать компоненты друг относительно друга. ConstraintLayout позволяет задавать связи между компонентами. Можно привязать верх кнопки к верху контейнера ConstraintLayout. Тогда кнопка будет наверху. А если привязать ещё и низ кнопки к низу контейнера, то кнопка будет в центре по вертикали, уравновешиваясь этими двумя связями.
Код activity_main.xml:
1 2 3 4 5 6 7 8 9 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> </androidx.constraintlayout.widget.ConstraintLayout> |
В Java-классе MainActivity устанавливается связь с файлом activity_main.xml при помощи метода setContentView(). Он задаёт, какой файл разметки будет использоваться в этой Activity в качестве интерфейса.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package com.androidapp.example; 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.activity_main); } } |
Получение ссылок на компоненты
Пока что в классе MainActivity пустовато. Там нет никаких компонентов. Ровно как и в activity_main.xml, если не считать одинокого ConstraintLayout. Давайте добавим пару компонентов. Откроем файл activity_main.xml и перейдём на вкладку Design.
Напишем симулятор школьной доски. Для этого понадобится добавить на экран 1 ImageView, 3 TextView, 2 EditText и 1 Button. Внесём их на экран из левой панельки:
Пока что IntelliJ IDEA ругается, так как для компонентов не настроены привязки. Это нормально. Скоро мы их настроим в коде xml.
Для главной части приложения – школьной доски – нужно скачать картинку школьной доски из интернета. Затем её необходимо поместить по пути Название проекта -> app -> src -> main -> res -> drawable.
Теперь подготовки окончены и можно написать xml-код для правильной настройки компонентов:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/mainLayout" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ImageView android:id="@+id/boardImageView" android:layout_width="match_parent" android:layout_height="280dp" android:src="@drawable/board" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="50dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"/> <Button android:id="@+id/buttonCalc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Рассчитать" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="90dp"/> <TextView android:id="@+id/textViewEquation" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="x + y = ?" android:textSize="58sp" android:textColor="@color/white" android:fontFamily="casual" app:layout_constraintTop_toTopOf="@+id/boardImageView" app:layout_constraintBottom_toBottomOf="@+id/boardImageView" app:layout_constraintStart_toStartOf="@+id/boardImageView" app:layout_constraintEnd_toEndOf="@+id/boardImageView"/> <TextView android:id="@+id/textViewX" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="x = " android:textSize="20sp" android:textColor="@color/black" android:fontFamily="serif" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="100dp" app:layout_constraintTop_toBottomOf="@+id/boardImageView" android:layout_marginTop="90dp"/> <TextView android:id="@+id/textViewY" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="y = " android:textSize="20sp" android:textColor="@color/black" android:fontFamily="serif" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="100dp" app:layout_constraintTop_toBottomOf="@+id/textViewX" android:layout_marginTop="30dp"/> <EditText android:id="@+id/editTextX" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="" android:ems="3" android:textSize="20sp" android:textColor="@color/black" android:fontFamily="serif" app:layout_constraintStart_toEndOf="@+id/textViewX" app:layout_constraintTop_toTopOf="@+id/textViewX" app:layout_constraintBottom_toBottomOf="@+id/textViewX"/> <EditText android:id="@+id/editTextY" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="" android:ems="3" android:textSize="20sp" android:textColor="@color/black" android:fontFamily="serif" app:layout_constraintStart_toEndOf="@+id/textViewY" app:layout_constraintTop_toTopOf="@+id/textViewY" app:layout_constraintBottom_toBottomOf="@+id/textViewY"/> </androidx.constraintlayout.widget.ConstraintLayout> |
Результат получился выдающийся. Итого есть ImageView с картинкой доски, и на ней расположен TextView с уравнением. Под доской есть две пары TextView–EditText для ввода x и y соответственно. Внизу экрана расположена кнопка “Рассчитать” для расчёта уравнения.
Теперь на компоненты, которые мы добавили в activity_main.xml, нужно получить ссылки в классе MainActivity. Всего добавлено было 7 компонентов. Но давайте подумаем: а так ли нам нужно обращаться прямо ко всем из них? Да, менять текст на доске впоследствии придётся, равно как считывать ввод пользователя в двух текстовых полях (x и y). Также придётся обрабатывать нажатия кнопки. Но всё остальные компоненты нам больше никак не пригодятся. Они просто должны быть на экране. Это ImageView с картинкой школьной доски и два TextView: “x = ” и “y = “. На них мы ссылки получать не будем – это было бы излишне.
Зайдём в MainActivity.java. Нам предстоит создать поля для компонентов интерфейса и создать метод для их привязки к компонентам в activity_main.xml. Получать ссылки на компоненты интерфейса нужно методом findViewById().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class MainActivity extends AppCompatActivity { private Button buttonCalculate; private TextView textViewOnBoard; private EditText editTextX; private EditText editTextY; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); defineComponents(); } /** * получение ссылок на графические компоненты */ private void defineComponents() { ConstraintLayout layout = findViewById(R.id.mainLayout); buttonCalculate = layout.findViewById(R.id.buttonCalc); textViewOnBoard = layout.findViewById(R.id.textViewEquation); editTextX = layout.findViewById(R.id.editTextX); editTextY = layout.findViewById(R.id.editTextY); } } |
Для начала в методе defineComponents() мы нашли главный Layout в activity_main.xml – ConstraintLayout. И уже затем на этом ConstraintLayout-е мы находили все остальные нужные нам компоненты.
Вот мы и получили ссылки на компоненты интерфейса. Дальше будем решать, что с ними делать.
Обработка событий
Обработчики событий чаще всего добавляют на кнопки. Событие при этом – клик по кнопке. Так же поступим и мы – добавим обработку события “клик по кнопке“. Это делается следующим образом:
1 2 3 |
button.setOnClickListener(view -> { // Действия при нажатии на кнопку }); |
Добавим в класс MainActivity обработчик нажатия на кнопку.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
public class MainActivity extends AppCompatActivity { private Button buttonCalculate; private TextView textViewOnBoard; private EditText editTextX; private EditText editTextY; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); defineComponents(); defineFunctionality(); } /** * определение функциональности */ private void defineFunctionality() { buttonCalculate.setOnClickListener(view -> { Toast.makeText(MainActivity.this, "Кнопка была нажата!", Toast.LENGTH_SHORT).show(); }); } /** * получение ссылок на графические компоненты */ private void defineComponents() { ConstraintLayout layout = findViewById(R.id.mainLayout); buttonCalculate = layout.findViewById(R.id.buttonCalc); textViewOnBoard = layout.findViewById(R.id.textViewEquation); editTextX = layout.findViewById(R.id.editTextX); editTextY = layout.findViewById(R.id.editTextY); } } |
Запустим приложение на телефоне. Интерфейс отображается корректно – всё на своих местах.
Если нажать кнопку “Рассчитать”, высветится уведомление “Кнопка была нажата!”. Причём это можно делать неограниченное количество раз: каждое нажатие на кнопку получит обработку и своё сообщение в уведомлении.
Такие же обработчики можно добавлять не только на кнопки. Можно добавить обработку клика по ImageView или TextView. Более того, типы событий бывают тоже разными. Мы рассматривали клик, но это может быть долгое нажатие, прокрутка, изменение текста (для EditText) и другие события.
Изменение параметров компонентов
Чтобы обработать ввод x и y от пользователя и повлиять на отображаемое уравнение, нужно изменить параметры компонентов. Получить текст из EditText-а можно методом getText(). Установить текст на TextView можно методом setText(). Также необходимо добавить обработку случаев, когда пользователь вводит не целые числа. Для этого введём обработку исключения блоком try-catch. Итог:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
public class MainActivity extends AppCompatActivity { private Button buttonCalculate; private TextView textViewOnBoard; private EditText editTextX; private EditText editTextY; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); defineComponents(); defineFunctionality(); } /** * определение функциональности */ private void defineFunctionality() { buttonCalculate.setOnClickListener(view -> changeEquation()); } private void changeEquation() { try { readAndUseEquationData(); } catch (NumberFormatException ex) { Toast.makeText(this, "Введите целые числа", Toast.LENGTH_SHORT).show(); } } private void readAndUseEquationData() { int x = readFromEditTextX(); int y = readFromEditTextY(); textViewOnBoard.setText(createTextForBoard(x, y)); } private String createTextForBoard(int x, int y) { int result = x + y; return x + " + " + y + " = " + result; } private int readFromEditTextX() { return Integer.parseInt(editTextX.getText().toString()); } private int readFromEditTextY() { return Integer.parseInt(editTextY.getText().toString()); } /** * получение ссылок на графические компоненты */ private void defineComponents() { ConstraintLayout layout = findViewById(R.id.mainLayout); buttonCalculate = layout.findViewById(R.id.buttonCalc); textViewOnBoard = layout.findViewById(R.id.textViewEquation); editTextX = layout.findViewById(R.id.editTextX); editTextY = layout.findViewById(R.id.editTextY); } } |
Теперь вы знаете, как управлять интерфейсом из Java-кода. Используйте метод findViewById() во благо. И пусть обработчики событий позволят вам создавать интерактивные предложения. Да пребудет с вами сила программирования!