В этом уроке:

- разбираем как можно использовать LayoutInflater

 

После изучения SQLite самое время приступить к изучению списков – List. Но перед этим полезно будет узнать про LayoutInflater. Это знание пригодится нам в создании расширенных списков. Также перед этим уроком рекомендую снова прочесть урок про LayoutParams, освежить знания.

LayoutInflater – это класс, который умеет из содержимого layout-файла создать View-элемент. Метод который это делает называется inflate. Есть несколько реализаций этого метода с различными параметрами. Но все они используют друг друга и результат их выполнения один – View.

Мы рассмотрим эту реализацию – public View inflate (int resource, ViewGroup root, boolean attachToRoot) 

Как видим, на вход метод принимает три параметра:

resource - ID layout-файла, который будет использован для создания View. Например - R.layout.main
root – родительский ViewGroup-элемент для создаваемого View. LayoutParams от этого ViewGroup присваиваются создаваемому View.
attachToRoot – присоединять ли создаваемый View к root. Если true, то root становится родителем создаваемого View. Т.е. это равносильно команде root.addView(View).  Если false – то создаваемый View просто получает LayoutParams от root, но его дочерним элементом не становится.

 

Посмотрим на практике.

 

Создадим проект:

Project name: P0401_LayoutInflater
Build Target: Android 2.3.3
Application name: LayoutInflater
Package name: ru.startandroid.develop.p0401layoutinflater
Create Activity: MainActivity

 

Открываем main.xml и рисуем такой экран:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">
    <LinearLayout
        android:id="@+id/linLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="20dp">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Linear Layout: ">
        </TextView>
    </LinearLayout>
    <RelativeLayout
        android:id="@+id/relLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="20dp">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Relative Layout: ">
        </TextView>
    </RelativeLayout>
</LinearLayout>

На экране две ViewGroup - linLayout и relLayout. В них по TextView с соответствующим текстом.

 

Создадим еще один layout-файл text.xml:

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tvLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:text="Layout with TextView">
</TextView>

Тут просто TextView без всяких ViewGroup. На нем мы и будем испытывать LayoutInflater.

 

 

Открываем MainActivity.java и пишем код:

package ru.startandroid.develop.p0401layoutinflater;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.TextView;

public class MainActivity extends Activity {
  
  final String LOG_TAG = "myLogs";
  
    /** Called when the activity is first created. */
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        LayoutInflater ltInflater = getLayoutInflater();
        View view = ltInflater.inflate(R.layout.text, null, false);
        LayoutParams lp = view.getLayoutParams();
        
        Log.d(LOG_TAG, "Class of view: " + view.getClass().toString());
        Log.d(LOG_TAG, "LayoutParams of view is null: " + (lp == null));
        Log.d(LOG_TAG, "Text of view: " + ((TextView) view).getText());
    }
}

Мы получаем LayoutInflater методом getLayoutInflater, используем его для получения View-элемента из layout-файла text.xml и считываем LayoutParams у свежесозданного view.

Обратите внимание на параметры, которые мы использовали для метода inflate. Мы указали ID layout-ресурса, передали null в качестве родительского элемента и, соответственно, привязка к родителю - false.

Все сохраним и запустим.

 

На экране ничего не изменилось. Т.к. мы конвертнули layout в view, но никуда его не поместили. Он просто висит в памяти.

 

Смотрим лог:

Class of view: class android.widget.TextView
LayoutParams of view is null: true
Text of view: Layout with TextView

Мы видим класс созданного элемента - TextView. Все верно - этот элемент и был в файле text.xml. Далее видим null вместо LayoutParams. Это произошло потому, что родителя в методе inflate мы указали null. А именно от родителя view и должен был получить LayoutParams. Третья строка лога показывает текст TextView. Он тот же, что и в layout-файле text.xml – все верно.

 

Давайте немного изменим программу. Будем добавлять наш созданный элемент в linLayout из main.xml. Делается это просто – командой addView.

LayoutParams lp = view.getLayoutParams();
        
LinearLayout linLayout = (LinearLayout) findViewById(R.id.linLayout);
linLayout.addView(view);
        
Log.d(LOG_TAG, "Class of view: " + view.getClass().toString());  

(добавляете только выделенные строки)

 

Мы нашли linLayout с экрана и добавили в него созданный с помощью LayoutInflater элемент.

 

Сохраняем, запускаем. Видим, что элемент добавился на экран в linLayout.

 

Теперь давайте попробуем указать родителя (root) при вызове метода inflate. Перепишем метод onCreate:

  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    LayoutInflater ltInflater = getLayoutInflater();

    LinearLayout linLayout = (LinearLayout) findViewById(R.id.linLayout);
    View view1 = ltInflater.inflate(R.layout.text, linLayout, false);
    LayoutParams lp1 = view1.getLayoutParams();

    Log.d(LOG_TAG, "Class of view1: " + view1.getClass().toString());
    Log.d(LOG_TAG, "Class of layoutParams of view1: " + lp1.getClass().toString());
    Log.d(LOG_TAG, "Text of view1: " + ((TextView) view1).getText());

    RelativeLayout relLayout = (RelativeLayout) findViewById(R.id.relLayout);
    View view2 = ltInflater.inflate(R.layout.text, relLayout, false);
    LayoutParams lp2 = view2.getLayoutParams();

    Log.d(LOG_TAG, "Class of view2: " + view2.getClass().toString());
    Log.d(LOG_TAG, "Class of layoutParams of view2: " + lp2.getClass().toString());
    Log.d(LOG_TAG, "Text of view2: " + ((TextView) view2).getText());
  }

 

Мы находим элементы linLayout и relLayout с экрана и с помощью LayoutInflater создаем два View-элемента из layout-файла text.xml. Для первого указываем root – linLayout, для второго relLayout. Но третий параметр attachToRoot оставляем false. Это значит, что созданный View-элемент получит LayoutParams от root-элемента, но не добавится к нему.

 

Все сохраним, запустим. На экране ничего не поменялось. Т.к. мы ни к чему новые элементы не добавляли и attachToRoot = false.

 

Смотрим лог:

Class of view1: class android.widget.TextView
Class of layoutParams of view1: class android.widget.LinearLayout$LayoutParams
Text of view1: Layout with TextView
Class of view2: class android.widget.TextView
Class of layoutParams of view2: class android.widget.RelativeLayout$LayoutParams
Text of view2: Layout with TextView

По логам видно, что класс созданных элементов – TextView. А класс LayoutParams различается. В первом случае – это LinearLayout$LayoutParams, т.к. в качестве root элемента в методе inflate мы указали linLayout, а это объект класса LinearLayout. Во втором случае класс LayoutParams у созданного элемента - RelativeLayout$LayoutParams. Потому, что в качестве root указали relLayout (класс RelativeLayout).

 

Теперь у нас два варианта, как добавить созданные view1 и view2 на экран.

1) Снова использовать методы addView

2) Передавать true в качестве третьего параметра метода inflate. Тогда созданный View-элемент будет добавлен к root.

 

Выберем второй вариант и внесем изменения в код:

  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    LayoutInflater ltInflater = getLayoutInflater();

    LinearLayout linLayout = (LinearLayout) findViewById(R.id.linLayout);
    View view1 = ltInflater.inflate(R.layout.text, linLayout, true);
    LayoutParams lp1 = view1.getLayoutParams();

    Log.d(LOG_TAG, "Class of view1: " + view1.getClass().toString());
    Log.d(LOG_TAG, "Class of layoutParams of view1: " + lp1.getClass().toString());

    RelativeLayout relLayout = (RelativeLayout) findViewById(R.id.relLayout);
    View view2 = ltInflater.inflate(R.layout.text, relLayout, true);
    LayoutParams lp2 = view2.getLayoutParams();

    Log.d(LOG_TAG, "Class of view2: " + view2.getClass().toString());
    Log.d(LOG_TAG, "Class of layoutParams of view2: " + lp2.getClass().toString());
  }

Передаем true в качестве третьего параметра в методе inflate и убираем строки выведения в лог текстов из TextView. Сейчас будет понятно почему.

Все сохраним и запустим приложение.

 

Как видим, созданные TextView появились в своих родителях, которых мы указали в методе inflate. В RelativeLayout элементы наложились друг на друга, т.к. мы не настроили расположение. В данный момент это не существенно. 

 

Смотрим лог:

Class of view1: class android.widget.LinearLayout
Class of layoutParams of view1: class android.widget.LinearLayout$LayoutParams
Class of view2: class android.widget.RelativeLayout
Class of layoutParams of view2: class android.widget.LinearLayout$LayoutParams

Обратите внимание на класс элементов. В первом случае - это LinearLayout, а во втором - RelativeLayout. Т.е. метод inflate вернул нам не созданные из layout-файла View-элементы, а те, что мы указывали как root. А созданные из layout-файла View элементы он добавил в root как дочерние аналогично команде addView. Это произошло потому, что мы указали true в третьем параметре (attachToRoot) метода inflate. 

Соответственно LayoutParams для view1 и view2 будет LinearLayout$LayoutParams, т.к. linLayout и relLayout имеют родителя LinearLayout. И LayoutParams берут от него.

Для закрепления темы на следующем уроке сделаем пример поинтереснее.

 

На следующем уроке:

- делаем свой вариант списка

getLayoutInflater 


Присоединяйтесь к нам в Telegram:

- в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance 

- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня




Language

Автор сайта

Дмитрий Виноградов

Подробнее можно посмотреть или почитать.

Никакие другие люди не имеют к этому сайту никакого отношения и просто занимаются плагиатом.

Социальные сети

 

В канале я публикую ссылки на интересные и полезные статьи по Android

В чате можно обсудить вопросы и проблемы, возникающие при разработке



Группа ВКонтакте



Поддержка проекта

Яндекс
410011180491924

WebMoney
R248743991365
Z551306702056

Paypal