Чому LayoutInflater ігнорує вказані нами параметри макета layout_width та layout_height?


168

У мене виникли серйозні проблеми з тим, щоб LayoutInflater працював так, як очікувалося, і так з іншими людьми: Як використовувати layoutinflator для додавання поглядів під час виконання? .

Чому LayoutInflater ігнорує вказані нами параметри компонування? Наприклад, чому не враховуються значення layout_widthта layout_heightзначення XML моїх ресурсів?


Правда - це болить чи я вибрав неправильне місце? Просто думав, що поділюся своїми результатами. Потрібно визнати, що навчальні посібники спеціально не згадуються про сторінку на веб-сайті ..
andig

3
дивіться останній абзац першого питання у тексті. опублікуйте це як запитання, а потім опублікуйте підручник як відповідь. Звичайно, ви можете відредагувати це питання, вирізаючи та вставляючи підручник у відповіді. Я підкажу, якщо ви виправите це.
bigstones

Відповіді:


381

Я досліджував цю проблему, посилаючись на документи LayoutInflater та встановлюючи невеликий зразок демонстраційного проекту. Наступні підручники показують, як динамічно заповнити макет за допомогою LayoutInflater.

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

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

  • Повернення : Кореневий вид завищеної ієрархії. Якщо корінь був поставлений і attachToRootє true, це корінь; інакше це корінь завищеного файлу 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. Виклик надути коренем не рівним nullі attachRoot=trueне завантажує параметри макета, але повертає кореневий об'єкт знову, що запобігає подальшим змінам макета для завантаженого об'єкта (якщо ви не зможете знайти його за допомогою findViewById()). Конвенція про дзвінки, яку ви, швидше за все, хотіли б використати, є такою:

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

Щоб вирішити проблеми з компонуванням , настійно рекомендується інспектор макета .


20
Відмінна відповідь. Працював на Android 3 роки і рахував і все-таки було чому навчитися з цього.
Рубін Скреттон

Привіт, чи є якийсь спосіб зробити те ж саме, що і з кодом Java, а не надувати R.layout. тому що у мене немає верстки. Я створив представлення з кодом java, і я хочу додати той самий вигляд протягом 300 разів.
Радж

1
@andig: Activityє підкласом, Contextа приклади відповіді - в обсязі Activity, тому для спрощення я замінив його getBaseContext()на this, ради цієї відповіді це еквівалентно.
Марцін Орловський

5
контейнер має layout_width та layout_height, встановлений на "match_parent"; потім коментар говорить "// результат: layout_height = wrap_content layout_width = match_parent". Я пропускаю що-небудь?
Marian Paździoch

1
Дякуємо за проведене дослідження та обмін результатами! Крім того, я другий питання Маріан.
LarsH

5

andig правильно, що загальною причиною ігнорування LayoutInflater вашого layout_params було б тому, що корінь не вказано. Багато хто думає, що ви можете передати нульовий корінь. Це прийнятно для кількох сценаріїв, таких як діалог, де ви не маєте доступу до root під час створення. Хорошим правилом, яке слід дотримуватися, є те, що якщо у вас є root, надайте його LayoutInflater.

Я написав про це поглиблену публікацію в блозі, яку ви можете перевірити тут:

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


1
This is acceptable for a few scenarios such as a dialogце було все, що мені потрібно
rookieDeveloper

0

хочу додати до основної відповіді вище.
Я намагався дотримуватися цього, але мій переробникView почав розтягувати кожен елемент на екрані,
мені довелося додати наступний рядок після надуття, щоб досягти мети

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

Я вже додав ці параметри xml, але він не працював правильно,
і з цим рядком все нормально

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.