Почему LayoutInflater игнорирует указанные мной параметры макета layout_width и layout_height?

168

У меня были серьезные проблемы с тем, чтобы LayoutInflater работал должным образом, как и другие люди: как использовать layoutinflator для добавления представлений во время выполнения? ,

Почему LayoutInflater игнорирует параметры макета, которые я указал? Например, почему значения layout_widthи layout_heightмои ресурсы XML не соблюдаются?

andig
источник
Правда - это больно или я выбрал не то место? Просто подумал, что поделюсь своими результатами. Должен признать, что учебники специально не упоминаются на странице
часто
3
см. последний абзац первого вопроса в faq. опубликуйте это как вопрос, а затем опубликуйте урок как ответ. Конечно, вы можете редактировать этот вопрос, вырезая и вставляя учебник в ответ. Я буду голосовать, если вы это исправите.
большие камни

Ответы:

381

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

Прежде чем мы начнем, посмотрим, как LayoutInflater.inflate()выглядят параметры:

  • ресурс : идентификатор загружаемого ресурса макета XML (например, R.layout.main_page)
  • root : Необязательное представление, чтобы быть родителем сгенерированной иерархии (если attachToRootесть true), или просто объект, который предоставляет набор LayoutParamsзначений для корня возвращаемой иерархии (если attachToRootесть false.)
  • attachToRoot : должна ли завышенная иерархия быть присоединена к корневому параметру? Если false, root используется только для создания правильного подкласса LayoutParamsдля корневого представления в XML.

  • Возвращает : корневой вид завышенной иерархии. Если root был указан и attachToRootесть true, это root; в противном случае это корень завышенного XML-файла.

Теперь для примера макета и кода.

Основной макет ( main.xml):

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

В этот контейнер добавлен отдельный TextView, видимый в виде маленького красного квадрата, если параметры макета успешно применяются из XML ( red.xml):

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="25dp"
    android:layout_height="25dp"
    android:background="#ff0000"
    android:text="red" />

Теперь LayoutInflaterиспользуется с несколькими вариантами параметров вызова

public class InflaterTest extends Activity {

    private View view;

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

      setContentView(R.layout.main);
      ViewGroup parent = (ViewGroup) findViewById(R.id.container);

      // result: layout_height=wrap_content layout_width=match_parent
      view = LayoutInflater.from(this).inflate(R.layout.red, null);
      parent.addView(view);

      // result: layout_height=100 layout_width=100
      view = LayoutInflater.from(this).inflate(R.layout.red, null);
      parent.addView(view, 100, 100);

      // result: layout_height=25dp layout_width=25dp
      // view=textView due to attachRoot=false
      view = LayoutInflater.from(this).inflate(R.layout.red, parent, false);
      parent.addView(view);

      // result: layout_height=25dp layout_width=25dp 
      // parent.addView not necessary as this is already done by attachRoot=true
      // view=root due to parent supplied as hierarchy root and attachRoot=true
      view = LayoutInflater.from(this).inflate(R.layout.red, parent, true);
    }
}

Фактические результаты изменений параметров задокументированы в коде.

ОПИСАНИЕ: Вызов LayoutInflaterбез указания корня приводит к раздутому вызову, игнорирующему параметры макета из XML. Вызов inflate с root не равен nullи attachRoot=trueзагружает параметры макета, но возвращает корневой объект снова, что предотвращает дальнейшие изменения макета загруженного объекта (если вы не можете найти его с помощью findViewById()). Поэтому соглашение о вызовах, которое вы, скорее всего, хотели бы использовать, таково:

loadedView = LayoutInflater.from(context)
                .inflate(R.layout.layout_to_load, parent, false);

Чтобы помочь с проблемами макета, настоятельно рекомендуется инспектор макета .

andig
источник
20
Отличный ответ. Работал над Android в течение 3 лет и считал, и у него было чему поучиться.
Рувим Скрэттон
Привет, есть ли способ сделать то же самое с помощью кода Java вместо надувания с помощью R.layout. потому что у меня нет макета. Я создал вид с помощью кода Java, и я хочу добавить один и тот же вид 300 раз.
Радж
1
@andig: Activityявляется подклассом, Contextи примеры ответа находятся в области видимости Activity, поэтому, чтобы упростить его, я заменил getBaseContext()на, thisпоскольку, ради этого ответа, это эквивалентно.
Марчин Орловский
5
контейнер имеет layout_width и layout_height, установленный в "match_parent"; затем комментарий говорит: "// result: layout_height = wrap_content layout_width = match_parent". Я скучаю по чему-то?
Marian Paździoch
1
Спасибо за исследование и обмен результатами! Кроме того, я второй вопрос Мариан.
LarsH
5

andig правильно, что общая причина игнорирования LayoutInflater ваших layout_params была бы, потому что корень не был указан. Многие люди думают, что вы можете передать null для root. Это приемлемо для нескольких сценариев, таких как диалог, когда у вас нет доступа к root во время создания. Однако следует соблюдать хорошее правило: если у вас есть root, передайте его LayoutInflater.

Я написал подробное сообщение в блоге об этом, которое вы можете проверить здесь:

https://www.bignerdranch.com/blog/understanding-androids-layoutinflater-inflate/

seanjfarrell
источник
1
This is acceptable for a few scenarios such as a dialogэто было все, что мне было нужно
rookieDeveloper
0

хочу добавить к основному ответу выше,
я пытался следовать ему, но мой recyclerView начал растягивать каждый элемент на экран, который
я должен был добавить следующую строку после надувания для достижения цели

itemLayoutView.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT));

Я уже добавил эти параметры в xml, но это не сработало правильно,
и с этой строкой все в порядке

Kirguduck
источник