Dlaczego LayoutInflater ignoruje parametry układu layout_width i layout_height, które określiłem?

168

Miałem poważny problem ze sprawieniem, aby LayoutInflater działał zgodnie z oczekiwaniami, podobnie jak inne osoby: Jak używać layoutinflatora do dodawania widoków w czasie wykonywania? .

Dlaczego LayoutInflater ignoruje określone przeze mnie parametry układu? Np. Dlaczego wartości layout_widthi layout_heightz moich zasobów XML nie są honorowane?

andig
źródło
To prawda - czy to boli, czy też wybrałem złe miejsce? Pomyślałem, że podzielę się wynikami. Muszę przyznać, że tutoriale nie są szczegółowo omówione na stronie z
często zadawanymi pytaniami
3
zobacz ostatni akapit pierwszego pytania w FAQ. opublikuj to jako pytanie, a następnie opublikuj samouczek jako odpowiedź. oczywiście możesz edytować to pytanie, wycinając i wklejając samouczek w odpowiedzi. Zagłosuję za, jeśli to naprawisz.
bigstones

Odpowiedzi:

381

Zbadałem ten problem, odwołując się do dokumentacji LayoutInflater i konfigurując mały przykładowy projekt demonstracyjny. Poniższe samouczki pokazują, jak dynamicznie wypełniać układ przy użyciu LayoutInflater.

Zanim zaczniemy, zobacz, jak LayoutInflater.inflate()wyglądają parametry:

  • zasób : identyfikator zasobu układu XML do załadowania (np. R.layout.main_page)
  • root : opcjonalny widok, który ma być elementem nadrzędnym wygenerowanej hierarchii (jeśli attachToRootjest true), lub po prostu obiekt, który dostarcza zestaw LayoutParamswartości dla katalogu głównego zwracanej hierarchii (jeśli attachToRootjest false).
  • attachToRoot : czy zawyżona hierarchia powinna być dołączona do parametru głównego? Jeśli false, root jest używany tylko do tworzenia poprawnej podklasy LayoutParamsdla widoku głównego w XML.

  • Zwroty : widok główny zawyżonej hierarchii. Jeśli podano root i attachToRootjest true, to jest to root; w przeciwnym razie jest to katalog główny zawyżonego pliku XML.

Teraz przykładowy układ i kod.

Główny układ ( 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>

Do tego kontenera dodano oddzielny TextView, widoczny jako mały czerwony kwadrat, jeśli parametry układu zostały pomyślnie zastosowane z 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" />

Teraz LayoutInflaterjest używany z kilkoma odmianami parametrów połączeń

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

Rzeczywiste wyniki zmian parametrów są udokumentowane w kodzie.

SKŁADNIA: Wywołanie LayoutInflaterbez określania głównych prowadzi do zawyżenia wywołania ignorując parametry układu z XML. Wywołanie inflate z elementem głównym nie jest równe nulli attachRoot=trueładuje parametry układu, ale ponownie zwraca obiekt główny, co zapobiega dalszym zmianom układu w załadowanym obiekcie (chyba że można go znaleźć za pomocą findViewById()). Dlatego najprawdopodobniej najprawdopodobniej chciałbyś użyć tej konwencji:

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

Aby pomóc w rozwiązaniu problemów z układem, wysoce zalecany jest Inspektor układu .

andig
źródło
20
Doskonała odpowiedź. Pracuję nad Androidem od 3 lat, liczę i wciąż muszę się czegoś z tego nauczyć.
Reuben Scratton
Cześć, czy istnieje sposób, aby zrobić to samo z kodem java zamiast nadmuchiwania za pomocą R.layout. ponieważ nie mam układu. Utworzyłem widok za pomocą kodu Java i chcę dodać ten sam widok 300 razy.
Raj
1
@andig: Activityjest podklasą Contexti przykłady odpowiedzi są w zakresie Activity, więc dla uproszczenia zastąpiłem getBaseContext()je this, ponieważ na potrzeby tej odpowiedzi jest równoważne.
Marcin Orłowski
5
kontener ma layout_width i layout_height ustawione na „match_parent”; następnie komentarz mówi „// result: layout_height = wrap_content layout_width = match_parent”. Brakuje mi czegoś?
Marian Paździoch
1
Dziękujemy za zebranie informacji i podzielenie się wynikami! Drugie pytanie Mariana.
LarsH
5

andig ma rację, że częstym powodem ignorowania przez LayoutInflater parametrów layout_params jest brak określenia katalogu głównego. Wiele osób uważa, że ​​jako root można podać null. Jest to dopuszczalne w przypadku kilku scenariuszy, takich jak okno dialogowe, w którym nie masz dostępu do roota w momencie tworzenia. Jednak dobrą zasadą jest to, że jeśli masz root, przekaż go LayoutInflater.

Napisałem na ten temat szczegółowy post na blogu, który możesz sprawdzić tutaj:

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

seanjfarrell
źródło
1
This is acceptable for a few scenarios such as a dialogto było wszystko, czego potrzebowałem
rookieDeveloper
0

chcę dodać do głównej odpowiedzi powyżej
Próbowałem podążać za tym, ale mój recykler zaczął rozciągać każdy element na ekran,
który musiałem dodać następną linię po nadmuchaniu, aby dotrzeć do celu

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

Dodałem już te parametry przez xml, ale nie działały poprawnie
iz tą linią wszystko jest w porządku

Kirguduck
źródło