Mengapa LayoutInflater mengabaikan parameter tata letak layout_width dan layout_height yang telah saya tentukan?

168

Saya mengalami kesulitan besar dalam membuat LayoutInflater berfungsi seperti yang diharapkan, dan begitu juga orang lain: Bagaimana cara menggunakan layoutinflator untuk menambahkan tampilan saat runtime? .

Mengapa LayoutInflater mengabaikan parameter tata letak yang telah saya tentukan? Misalnya mengapa layout_widthdan layout_heightnilai - nilai dari sumber daya saya XML tidak dihormati?

andig
sumber
Benar - apakah itu sakit atau apakah saya memilih tempat yang salah? Hanya berpikir saya akan membagikan hasil saya. Harus mengakui tutorial tidak secara khusus disebutkan di halaman faq ..
andig
3
lihat paragraf terakhir dari pertanyaan pertama dalam faq. mempostingnya sebagai pertanyaan dan kemudian memposting tutorial sebagai jawaban. tentu saja, Anda dapat mengedit pertanyaan ini memotong dan menempelkan tutorial di jawabannya. Saya akan angkat suara jika Anda memperbaiki ini.
bigstones

Jawaban:

381

Saya telah menyelidiki masalah ini, merujuk pada dokumen LayoutInflater dan membuat proyek percontohan sampel kecil. Tutorial berikut menunjukkan cara mengisi tata letak secara dinamis menggunakan LayoutInflater.

Sebelum kita mulai, lihat seperti apa LayoutInflater.inflate()parameternya:

  • sumber daya : ID untuk sumber daya tata letak XML untuk memuat (misalnya, R.layout.main_page)
  • root : Tampilan opsional untuk menjadi induk dari hierarki yang dihasilkan (jika attachToRootada true), atau hanya objek yang menyediakan seperangkat LayoutParamsnilai untuk root dari hierarki yang dikembalikan (jika attachToRootada false.)
  • attachToRoot : Apakah hirarki yang meningkat harus dilampirkan ke parameter root? Jika false, root hanya digunakan untuk membuat subclass yang benar LayoutParamsuntuk tampilan root dalam XML.

  • Pengembalian : Tampilan root dari hierarki yang meningkat. Jika akar disediakan dan attachToRootadalah true, ini adalah akar; jika tidak, ini adalah akar dari file XML yang dipompa.

Sekarang untuk tata letak sampel dan kode.

Tata letak utama ( 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>

Ditambahkan ke wadah ini adalah TextView terpisah, terlihat sebagai kotak merah kecil jika parameter tata letak berhasil diterapkan dari 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" />

Sekarang LayoutInflaterdigunakan dengan beberapa variasi parameter panggilan

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);
    }
}

Hasil aktual dari variasi parameter didokumentasikan dalam kode.

SYNOPSIS: Memanggil LayoutInflatertanpa menentukan lead root untuk mengembang panggilan mengabaikan parameter tata letak dari XML. Memanggil mengembang dengan root tidak sama nulldan attachRoot=truememuat parameter tata letak, tetapi mengembalikan objek root lagi, yang mencegah perubahan tata letak lebih lanjut ke objek yang dimuat (kecuali Anda dapat menemukannya menggunakan findViewById()). Karenanya, konvensi panggilan yang kemungkinan besar ingin Anda gunakan adalah yang ini:

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

Untuk membantu dengan masalah tata letak, Inspektur Tata Letak sangat dianjurkan.

andig
sumber
20
Jawaban yang sangat bagus. Sudah bekerja di Android selama 3 tahun dan terus bertambah dan masih harus belajar dari ini.
Reuben Scratton
Hai apakah ada cara untuk melakukan hal yang sama dengan kode java bukannya menggembungkan dengan R.layout. karena saya tidak punya tata letak. Saya telah membuat tampilan dengan kode java dan saya ingin menambahkan tampilan yang sama sebanyak 300 kali.
Raj
1
@andig: Activityadalah subclass dari Contextdan contoh jawaban ada di ruang lingkup Activity, jadi untuk membuatnya lebih mudah saya diganti getBaseContext()dengan this, demi jawaban ini, itu setara.
Marcin Orlowski
5
kontainer memiliki layout_width dan layout_height diatur ke "match_parent"; lalu komentar mengatakan "// hasil: layout_height = wrap_content layout_width = match_parent". Apakah saya kehilangan sth?
Marian Paździoch
1
Terima kasih telah melakukan penelitian dan membagikan hasilnya! Juga, saya pertanyaan kedua Marian.
LarsH
5

andig benar bahwa alasan umum LayoutInflater mengabaikan layout_params Anda adalah karena root tidak ditentukan. Banyak orang berpikir Anda dapat melewatkan null untuk root. Ini dapat diterima untuk beberapa skenario seperti dialog, di mana Anda tidak memiliki akses ke root pada saat pembuatan. Namun, aturan yang baik untuk diikuti adalah jika Anda memiliki root, berikan ke LayoutInflater.

Saya menulis posting blog yang mendalam tentang hal ini yang dapat Anda lihat di sini:

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

seanjfarrell
sumber
1
This is acceptable for a few scenarios such as a dialogitu yang saya butuhkan
pemula
0

ingin menambah jawaban utama di atas
saya mencoba untuk mengikutinya tetapi recyclerView saya mulai meregangkan setiap item ke layar
saya harus menambahkan baris berikutnya setelah menggembungkan untuk mencapai tujuan

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

Saya sudah menambahkan params ini dengan xml tetapi tidak bekerja dengan benar
dan dengan baris ini semuanya ok

Kirguduck
sumber