Что делает LayoutInflater в Android? - PullRequest
315 голосов
/ 13 августа 2010

Какая польза от LayoutInflater в Android?

Ответы [ 15 ]

269 голосов
/ 13 августа 2010

Класс LayoutInflater используется для создания экземпляра XML-файла макета в соответствующих объектах View.

Другими словами, он принимает в качестве входного файла XML и создает из него объекты View.

161 голосов
/ 13 августа 2010

Когда вы используете пользовательское представление в ListView, вы должны определить макет строки.Вы создаете xml, куда вы помещаете виджеты Android, а затем в коде адаптера вы должны сделать что-то вроде этого:

public MyAdapter(Context context, List<MyObject> objects) extends ArrayAdapter {
  super(context, 1, objects);
  /* We get the inflator in the constructor */
  mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
  View view;
  /* We inflate the xml which gives us a view */
  view = mInflater.inflate(R.layout.my_list_custom_row, parent, false);

  /* Get the item in the adapter */
  MyObject myObject = getItem(position);

  /* Get the widget with id name which is defined in the xml of the row */
  TextView name = (TextView) view.findViewById(R.id.name);

  /* Populate the row's xml with info from the item */
  name.setText(myObject.getName());

  /* Return the generated view */
  return view;
}

Подробнее в официальной документации .

122 голосов
/ 06 января 2017

Что делает LayoutInflator?

Когда я впервые начал программировать на Android, меня действительно смутили LayoutInflater и findViewById. Иногда мы использовали один, а иногда другой.

  • LayoutInflater используется для создания нового View (или Layout) объекта из одного из ваших XML-макетов.
  • findViewById просто дает вам ссылку на вид, который уже был создан. Вы можете подумать, что вы еще не создали ни одного представления, но всякий раз, когда вы вызываете setContentView в onCreate, макет действия вместе с его подпредставлениями раздувается (создается) за кулисами.

Так что, если представление уже существует, используйте findViewById. Если нет, то создайте его с помощью LayoutInflater.

* +1025 * Пример

Вот мини-проект, который я сделал, который показывает как LayoutInflater, так и findViewById в действии. Без специального кода макет выглядит следующим образом.

enter image description here

Синий квадрат - это пользовательский макет, вставленный в основной макет с помощью include (подробнее см. здесь ). Он был раздут автоматически, потому что он является частью представления содержимого. Как видите, в коде нет ничего особенного.

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

Теперь давайте надуем (создадим) еще одну копию нашего пользовательского макета и добавим ее.

enter image description here

LayoutInflater inflater = getLayoutInflater();
View myLayout = inflater.inflate(R.layout.my_layout, mainLayout, false);

Чтобы надуть новый макет представления, все, что я сделал, это сказал инфлятору имя моего xml-файла (my_layout), родительский макет, к которому я хочу добавить его (mainLayout), и что я не Я на самом деле не хочу его добавлять (false). (Я мог бы также установить родительский элемент на null, но тогда параметры макета корневого представления моей пользовательской компоновки будут игнорироваться.)

Здесь снова в контексте.

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // inflate the main layout for the activity
        setContentView(R.layout.activity_main);

        // get a reference to the already created main layout
        LinearLayout mainLayout = (LinearLayout) findViewById(R.id.activity_main_layout);

        // inflate (create) another copy of our custom layout
        LayoutInflater inflater = getLayoutInflater();
        View myLayout = inflater.inflate(R.layout.my_layout, mainLayout, false);

        // make changes to our custom layout and its subviews
        myLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.colorAccent));
        TextView textView = (TextView) myLayout.findViewById(R.id.textView);
        textView.setText("New Layout");

        // add our custom layout to the main layout
        mainLayout.addView(myLayout);
    }
}

Обратите внимание, как findViewById используется только после того, как макет уже накачан.

Дополнительный код

Вот XML для примера выше.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main_layout"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">

    <!-- Here is the inserted layout -->
    <include layout="@layout/my_layout"/>

</LinearLayout>

my_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:background="@color/colorPrimary">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:padding="5dp"
        android:textColor="@android:color/white"
        android:text="My Layout"/>

</RelativeLayout>

Когда вам нужен LayoutInflater

  • Чаще всего большинство людей используют его в RecyclerView. (См. Эти RecyclerView примеры для списка или сетки .) Вы должны надуть новый макет для каждого видимого элемента в списке или сетке.
  • Вы также можете использовать инфлятор, если у вас есть сложный макет, который вы хотите добавить программно (как мы это делали в нашем примере). Вы можете сделать все это в коде, но сначала гораздо проще определить его в xml, а затем просто накачать.
30 голосов
/ 17 марта 2014

LayoutInflater.inflate () предоставляет средство для преобразования файла res / layout / *. Xml, определяющего представление, в фактический объект View, используемый в исходном коде вашего приложения.

два основных шага: получить инфлятора затем раздувать ресурс

как вы получаете инфлятор?

LayoutInflater inflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

Как получить представление, предполагая, что xml-файл - "list_item.xml"?

View view = inflater.inflate(R.layout.list_item, parent, false);
22 голосов
/ 22 декабря 2012

Вот еще один пример, похожий на предыдущий, но расширенный для дальнейшей демонстрации параметров раздувания и динамического поведения, которые он может предоставить.

Предположим, что ваш макет строки ListView может иметь переменное количество TextViews. Поэтому сначала вы надуваете базовый элемент View (как в предыдущем примере), а затем динамически зацикливаетесь, добавляя TextViews во время выполнения. Использование android: layout_weight дополнительно выравнивает все идеально.

Вот ресурсы Layouts:

list_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:orientation="horizontal" >
    <TextView 
        android:id="@+id/field1"
        android:layout_width="0dp"  
        android:layout_height="wrap_content" 
        android:layout_weight="2"/>
    <TextView 
        android:id="@+id/field2"
        android:layout_width="0dp"  
        android:layout_height="wrap_content" 
        android:layout_weight="1"
/>
</LinearLayout>

schedule_layout.xml

<?xml version="1.0" encoding="utf-8"?>
   <TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="0dp"  
    android:layout_height="wrap_content" 
    android:layout_weight="1"/>

Переопределить getView метод в расширении класса BaseAdapter

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    LayoutInflater inflater = activity.getLayoutInflater();
    View lst_item_view = inflater.inflate(R.layout.list_layout, null);
    TextView t1 = (TextView) lst_item_view.findViewById(R.id.field1);
    TextView t2 = (TextView) lst_item_view.findViewById(R.id.field2);
    t1.setText("some value");
    t2.setText("another value");

    // dinamically add TextViews for each item in ArrayList list_schedule
    for(int i = 0; i < list_schedule.size(); i++){
        View schedule_view = inflater.inflate(R.layout.schedule_layout, (ViewGroup) lst_item_view, false);
        ((TextView)schedule_view).setText(list_schedule.get(i));
        ((ViewGroup) lst_item_view).addView(schedule_view);
    }
    return lst_item_view;
}

Примечание различные вызовы метода инфляции:

inflater.inflate(R.layout.list_layout, null); // no parent
inflater.inflate(R.layout.schedule_layout, (ViewGroup) lst_item_view, false); // with parent preserving LayoutParams
12 голосов
/ 03 марта 2012

Этот класс используется для создания экземпляра XML-файла макета в соответствующие ему View объекты. Он никогда не используется напрямую - используйте getLayoutInflater() или getSystemService(String), чтобы извлечь стандартный экземпляр LayoutInflater, который уже подключен к текущему контексту и правильно настроен для устройства, на котором вы работаете. Например:

LayoutInflater inflater = (LayoutInflater)context.getSystemService
      (Context.LAYOUT_INFLATER_SERVICE);

Ссылка: http://developer.android.com/reference/android/view/LayoutInflater.html

8 голосов
/ 23 сентября 2014

Накачивание означает чтение XML-файла, который описывает макет (или элемент графического интерфейса пользователя), и создание реальных объектов, которые ему соответствуют, и, таким образом, сделать объект видимым в приложении Android.

final Dialog mDateTimeDialog = new Dialog(MainActivity.this);

// Inflate the root layout
final RelativeLayout mDateTimeDialogView = (RelativeLayout) getLayoutInflater().inflate(R.layout.date_time_dialog, null);

// Grab widget instance
final DateTimePicker mDateTimePicker = (DateTimePicker) mDateTimeDialogView.findViewById(R.id.DateTimePicker);

Этофайл может быть сохранен как date_time_dialog.xml :

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/DateTimeDialog" android:layout_width="100px"
    android:layout_height="wrap_content">
    <com.dt.datetimepicker.DateTimePicker
            android:id="@+id/DateTimePicker" android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
    <LinearLayout android:id="@+id/ControlButtons"
            android:layout_width="fill_parent" android:layout_height="wrap_content"
            android:layout_below="@+id/DateTimePicker"
            android:padding="5dip">
            <Button android:id="@+id/SetDateTime" android:layout_width="0dip"
                    android:text="@android:string/ok" android:layout_weight="1"
                    android:layout_height="wrap_content"
                   />
            <Button android:id="@+id/ResetDateTime" android:layout_width="0dip"
                    android:text="Reset" android:layout_weight="1"
                    android:layout_height="wrap_content"
                    />
            <Button android:id="@+id/CancelDialog" android:layout_width="0dip"
                    android:text="@android:string/cancel" android:layout_weight="1"
                    android:layout_height="wrap_content"
                     />
    </LinearLayout>

Этот файл можно сохранить как date_time_picker.xml :

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="wrap_content" `enter code here`
    android:padding="5dip" android:id="@+id/DateTimePicker">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:baselineAligned="true"
android:orientation="horizontal">

    <LinearLayout
    android:id="@+id/month_container"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="1dp"
    android:layout_marginTop="5dp"
    android:layout_marginRight="5dp"
    android:layout_marginBottom="5dp"
    android:gravity="center"
    android:orientation="vertical">
    <Button
        android:id="@+id/month_plus"
        android:layout_width="45dp"
        android:layout_height="45dp"  
        android:background="@drawable/image_button_up_final"/>
    <EditText
        android:id="@+id/month_display"
        android:layout_width="45dp"
        android:layout_height="35dp"
        android:background="@drawable/picker_middle"
        android:focusable="false"
        android:gravity="center"
        android:singleLine="true"
        android:textColor="#000000">
    </EditText>
    <Button
        android:id="@+id/month_minus"
        android:layout_width="45dp"
        android:layout_height="45dp"       
        android:background="@drawable/image_button_down_final"/>
</LinearLayout>
<LinearLayout
    android:id="@+id/date_container"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="0.5dp"
    android:layout_marginTop="5dp"
    android:layout_marginRight="5dp"
    android:layout_marginBottom="5dp"
    android:gravity="center"
    android:orientation="vertical">
    <Button
        android:id="@+id/date_plus"
        android:layout_width="45dp"
        android:layout_height="45dp"       
        android:background="@drawable/image_button_up_final"/>
    <EditText
        android:id="@+id/date_display"
        android:layout_width="45dp"
        android:layout_height="35dp"
        android:background="@drawable/picker_middle"
        android:gravity="center"
        android:focusable="false"
        android:inputType="number"
        android:textColor="#000000"
        android:singleLine="true"/>
    <Button
        android:id="@+id/date_minus"
        android:layout_width="45dp"
        android:layout_height="45dp"      
        android:background="@drawable/image_button_down_final"/>
</LinearLayout>
<LinearLayout
    android:id="@+id/year_container"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="0.5dp"
    android:layout_marginTop="5dp"
    android:layout_marginRight="5dp"
    android:layout_marginBottom="5dp"
    android:gravity="center"
    android:orientation="vertical">
    <Button
        android:id="@+id/year_plus"
        android:layout_width="45dp"
        android:layout_height="45dp"       
            android:background="@drawable/image_button_up_final"/>
    <EditText
        android:id="@+id/year_display"
        android:layout_width="45dp"
        android:layout_height="35dp"
        android:background="@drawable/picker_middle"
        android:gravity="center"
        android:focusable="false"
        android:inputType="number"
        android:textColor="#000000"
        android:singleLine="true"/>
    <Button
        android:id="@+id/year_minus"
        android:layout_width="45dp"
        android:layout_height="45dp"       
        android:background="@drawable/image_button_down_final"/>
</LinearLayout>
<LinearLayout
        android:id="@+id/hour_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:gravity="center"
        android:orientation="vertical">
        <Button
            android:id="@+id/hour_plus"
            android:layout_width="45dp"
            android:layout_height="45dp"          
            android:background="@drawable/image_button_up_final"/>
        <EditText
            android:id="@+id/hour_display"
            android:layout_width="45dp"
            android:layout_height="35dp"
            android:background="@drawable/picker_middle"
            android:gravity="center"
            android:focusable="false"
            android:inputType="number"
            android:textColor="#000000"
            android:singleLine="true">
        </EditText>
        <Button
            android:id="@+id/hour_minus"
            android:layout_width="45dp"
            android:layout_height="45dp"       
            android:background="@drawable/image_button_down_final"/>
    </LinearLayout>
    <LinearLayout
        android:id="@+id/min_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="0.35dp"
        android:layout_marginTop="5dp"
        android:layout_marginRight="5dp"
        android:layout_marginBottom="5dp"
        android:gravity="center"
        android:orientation="vertical">
        <Button
            android:id="@+id/min_plus"
            android:layout_width="45dp"
            android:layout_height="45dp"       
            android:background="@drawable/image_button_up_final"/>
        <EditText
            android:id="@+id/min_display"
            android:layout_width="45dp"
            android:layout_height="35dp"
            android:background="@drawable/picker_middle"
            android:gravity="center"
            android:focusable="false"
            android:inputType="number"
            android:textColor="#000000"
            android:singleLine="true"/>
        <Button
            android:id="@+id/min_minus"
            android:layout_width="45dp"
            android:layout_height="45dp"       
            android:background="@drawable/image_button_down_final"/>
    </LinearLayout>

    <LinearLayout 
        android:id="@+id/meridiem_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="0.35dp"
        android:layout_marginTop="5dp"
        android:layout_marginRight="5dp"
        android:layout_marginBottom="5dp"
        android:gravity="center"
        android:orientation="vertical">
        <ToggleButton 
            android:id="@+id/toggle_display"
            style="@style/SpecialToggleButton"
            android:layout_width="40dp"
            android:layout_height="32dp"
            android:layout_marginLeft="5dp"
            android:layout_marginTop="45dp"
            android:layout_marginRight="5dp"
            android:layout_marginBottom="5dp"
            android:padding="5dp"
            android:gravity="center"
            android:textOn="@string/meridiem_AM"
            android:textOff="@string/meridiem_PM"
            android:checked="true"/>

           <!--  android:checked="true" --> 

    </LinearLayout>
</LinearLayout>
</RelativeLayout>

Класс MainActivity, сохраненный как MainActivity.java :

public class MainActivity extends Activity {
    EditText editText;
    Button button_click;
    public static Activity me = null;
    String meridiem;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editText = (EditText)findViewById(R.id.edittext1);
        button_click = (Button)findViewById(R.id.button1);
        button_click.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view){
                final Dialog mDateTimeDialog = new Dialog(MainActivity.this);
                final RelativeLayout mDateTimeDialogView = (RelativeLayout)   getLayoutInflater().inflate(R.layout.date_time_dialog, null);
                final DateTimePicker mDateTimePicker = (DateTimePicker) mDateTimeDialogView.findViewById(R.id.DateTimePicker);
                // mDateTimePicker.setDateChangedListener();
                ((Button) mDateTimeDialogView.findViewById(R.id.SetDateTime)).setOnClickListener(new OnClickListener() {
                    public void onClick(View v) {
                        mDateTimePicker.clearFocus();
                        int hour = mDateTimePicker.getHour();
                        String result_string = mDateTimePicker.getMonth() +" "+   String.valueOf(mDateTimePicker.getDay()) + ", " + String.valueOf(mDateTimePicker.getYear())
                        + "  " +(mDateTimePicker.getHour()<=9? String.valueOf("0"+mDateTimePicker.getHour()) : String.valueOf(mDateTimePicker.getHour())) + ":" + (mDateTimePicker.getMinute()<=9?String.valueOf("0"+mDateTimePicker.getMinute()):String.valueOf(mDateTimePicker.getMinute()))+" "+mDateTimePicker.getMeridiem();
                        editText.setText(result_string);
                        mDateTimeDialog.dismiss();
                    }
                });
                // Cancel the dialog when the "Cancel" button is clicked
                ((Button) mDateTimeDialogView.findViewById(R.id.CancelDialog)).setOnClickListener(new OnClickListener() {
                    public void onClick(View v) {
                        // TODO Auto-generated method stub
                        mDateTimeDialog.cancel();
                    }
                });
                // Reset Date and Time pickers when the "Reset" button is clicked
                ((Button) mDateTimeDialogView.findViewById(R.id.ResetDateTime)).setOnClickListener(new OnClickListener() {
                    public void onClick(View v) {
                        // TODO Auto-generated method stub
                        mDateTimePicker.reset();
                    }
                });

                // Setup TimePicker
                // No title on the dialog window
                mDateTimeDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
                // Set the dialog content view
                mDateTimeDialog.setContentView(mDateTimeDialogView);
                // Display the dialog
                mDateTimeDialog.show();
            }
        });
    }
}
6 голосов
/ 02 февраля 2016

Что делает инфлятор

Он принимает макет xml в качестве входных данных (скажем) и преобразует его в объект View.

Зачем нужно

Давайте подумаем сценарий, в котором нам нужно создать собственный просмотр списка. Теперь каждый ряд должен быть нестандартным. Но как мы можем это сделать. Невозможно назначить макет xml строке списка. Итак, мы создаем объект View. Таким образом, мы можем получить доступ к элементам в нем (textview, imageview и т. Д.), А также назначить объект в виде строки listview

Итак, всякий раз, когда нам нужно где-то назначить объект типа представления, и у нас есть свой собственный дизайн XML, мы просто конвертируем его в объект с помощью inflater и используем его.

5 голосов
/ 07 января 2014

вот пример для получения ссылки на корневой вид макета, раздувать и использовать его с setContentView (View view)

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    LayoutInflater li=getLayoutInflater();
    View rootView=li.inflate(R.layout.activity_main,null);
    setContentView(rootView);


}
4 голосов
/ 04 марта 2019

LayoutInflater - это класс, используемый для создания экземпляра XML-файла макета в соответствующих объектах представления, которые могут использоваться в программах Java.Проще говоря, есть два способа создания пользовательского интерфейса в Android.Один из них статический, а другой динамический или программный.Предположим, у нас есть простой макет main.xml, имеющий один textview и один edittext следующим образом.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/layout1"
    >
<TextView
        android:id="@+id/namelabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Enter your name"
        android:textAppearance="?android:attr/textAppearanceLarge" >
    </TextView>
    <EditText
        android:id="@+id/name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_marginTop="14dp"
        android:ems="10">
    </EditText>
</LinearLayout>

Мы можем отобразить этот макет в статическом виде с помощью

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

AДинамический способ создания представления означает, что представление не упоминается в нашем main.xml, но мы хотим показать это во время выполнения.Например, у нас есть другой XML в папке макета, как footer.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/TextView1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:text="Add your record"
    android:textSize="24sp" >
 </TextView>

Мы хотим показать это текстовое поле во время выполнения в нашем основном пользовательском интерфейсе.Так что здесь мы будем раздувать text.xml.Посмотрите, как:

public void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  final LayoutInflater  inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  TextView t = (TextView)inflater.inflate(R.layout.footer,null);

  lLayout = (LinearLayout)findViewById(R.id.layout1);
  lLayout.addView(t);

Здесь я использовал getSystemService (String) для получения экземпляра LayoutInflater.Я также могу использовать getLayoutInflator () для раздувания вместо использования getSystemService (String), как показано ниже:

LayoutInflator inflater = getLayoutInflater();
TextView t = (TextView) inflater.inflate(R.layout.footer, null);
lLayout.addView(t);
...