Одна layout может содержать другую layout. Для этого применяется элемент include.
Например, добавим в папку res/layout два файла layout, которые пусть будут называться text_panel.xml и button_panel.xml:
В файле text_panel.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" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/clicksText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="30sp" android:text="0 Clicks" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
По сути здесь просто определено поле TextView для вывода текста.
В файле button_panel.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" android:layout_width="wrap_content" android:layout_height="wrap_content"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Click" android:onClick="onClick" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
Здесь определена кнопка, нажатия которой мы будем обрабатывать.
Основным файлом разметки, который определяет интерфейс приложения, по-прежнему является 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" android:padding="16dp" tools:context=".MainActivity"> <include android:id="@+id/textView" layout="@layout/text_panel" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toTopOf="@+id/button" /> <include android:id="@+id/button" layout="@layout/button_panel" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView" /> </androidx.constraintlayout.widget.ConstraintLayout>
С помощью ConstraintLayout весь интерфейс здесь организуется в виде вертикального стека. С помощью элементов include внутрь ConstraintLayout добавляется содержимое файлов text_panel.xml и button_panel.xml. Для указания названия файла применяется атрибут layout.
Это все равно, что если бы мы напрямую вместо элемента include добавили содержимое файлов. Однако такой способ имеет свои преимущества. Например, какая-то часть разметки, группа элементов управления может повторяться в различных activity. И чтобы не определять по сто раз эти элементы, можно вынести их в отдельный файл layout и с помощью include подключать их.
После добавления в ConstraintLayout к элементам include можно применять все те стандартные атрибуты, которые применяются в этом контейнере к вложенным элементам, например, настроить размеры, расположение. Также стоит отметить, что добавлять внешние layout можно не только в ConstraintLayout, но и в другие контейнеры (LinearLayout, RelativeLayout и т.д.)
Также изменим код MainActivity:
package com.example.viewapp; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.TextView; public class MainActivity extends AppCompatActivity { int clicks = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void onClick(View view){ TextView clicksText = findViewById(R.id.clicksText); clicks++; clicksText.setText(clicks + " Clicks"); } }
В MainActivity мы можем обращаться к элементам во вложенных файлах layout. Например, мы можем установить обработчик нажатия кнопки, в котором при нажатии изменять текст в TextView.
При этом мы несколько раз можем добавлять в один файл layout другой файл layout. Для этого вначале изменим файл button_panel.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" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#3F51B5" android:paddingTop="10dp" android:paddingBottom="10dp"> <Button android:id="@+id/clickBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
И изменим файл 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" android:padding="16dp" tools:context=".MainActivity"> <include layout="@layout/text_panel" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> <include layout="@layout/button_panel" android:id="@+id/plus_button" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintRight_toLeftOf="@+id/minus_button"/> <include layout="@layout/button_panel" android:id="@+id/minus_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="36dp" app:layout_constraintLeft_toRightOf="@id/plus_button" app:layout_constraintBottom_toBottomOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
Теперь файл button_panel.xml добавляется два раза. Важно, что при добавлении этого файла каждому элементу include присвоен определенный id. По этому id мы сможем узнать, о каком именно элементе include идет речь.
Также изменим MainActivity:
package com.example.viewapp; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends AppCompatActivity { int clicks = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); View plusButtonView = findViewById(R.id.plus_button); View minusButtonView = findViewById(R.id.minus_button); TextView clicksText = findViewById(R.id.clicksText); Button plusButton = plusButtonView.findViewById(R.id.clickBtn); Button minusButton = minusButtonView.findViewById(R.id.clickBtn); plusButton.setText("+"); minusButton.setText("-"); plusButton.setOnClickListener(v -> { clicks++; clicksText.setText(clicks + " Clicks"); }); minusButton.setOnClickListener(v -> { clicks--; clicksText.setText(clicks + " Clicks"); }); } }
Здесь вначале мы получаем отдельные элементы include по id. Затем в рамках этих элементов получаем кнопку. После этого мы можем установить у кнопко любой текст и повесить обработчик события нажатия. И таким образом, поведение обеих кнопок будет различаться.