Pourquoi LayoutInflater ignore-t-il les paramètres de disposition layout_width et layout_height que j'ai spécifiés?

168

J'ai eu de sérieux problèmes pour faire fonctionner LayoutInflater comme prévu, tout comme d'autres personnes: Comment utiliser layoutinflator pour ajouter des vues au moment de l'exécution? .

Pourquoi LayoutInflater ignore-t-il les paramètres de mise en page que j'ai spécifiés? Par exemple, pourquoi les valeurs layout_widthet layout_heightde mes ressources XML ne sont-elles pas respectées?

Andig
la source
Est-ce que ça fait mal ou ai-je choisi le mauvais endroit? Je pensais juste partager mes résultats. Doit admettre que les tutoriels ne sont pas spécifiquement mentionnés sur la page
FAQ
3
voir le dernier paragraphe de la première question dans la FAQ. postez-le sous forme de question, puis postez le didacticiel en tant que réponse. bien sûr, vous pouvez modifier cette question en coupant et collant le didacticiel dans la réponse. Je voterai si vous corrigez cela.
bigstones

Réponses:

381

J'ai étudié ce problème, en me référant aux documents LayoutInflater et en configurant un petit exemple de projet de démonstration. Les didacticiels suivants montrent comment remplir dynamiquement une mise en page à l'aide de LayoutInflater.

Avant de commencer, voyez à quoi LayoutInflater.inflate()ressemblent les paramètres:

  • resource : ID pour une ressource de mise en page XML à charger (par exemple, R.layout.main_page)
  • root : vue facultative pour être le parent de la hiérarchie générée (si attachToRootest true), ou bien simplement un objet qui fournit un ensemble de LayoutParamsvaleurs pour la racine de la hiérarchie retournée (si attachToRootest false.)
  • attachToRoot : si la hiérarchie gonflée doit être attachée au paramètre racine? Si false, root n'est utilisé que pour créer la sous-classe correcte de LayoutParamspour la vue racine dans le XML.

  • Renvoie : La vue racine de la hiérarchie gonflée. Si root a été fourni et l' attachToRootest true, c'est root; sinon, c'est la racine du fichier XML gonflé.

Maintenant, pour l'exemple de mise en page et de code.

Disposition principale ( 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>

Un TextView séparé est ajouté à ce conteneur, visible sous forme de petit carré rouge si les paramètres de mise en page sont correctement appliqués à partir de 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" />

Maintenant LayoutInflaterest utilisé avec plusieurs variantes de paramètres d'appel

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

Les résultats réels des variations de paramètres sont documentés dans le code.

SYNOPSIS: Appeler LayoutInflatersans spécifier la racine conduit à gonfler l'appel en ignorant les paramètres de mise en page du XML. L'appel de inflate avec root n'est pas égal nullet attachRoot=truecharge les paramètres de mise en page, mais renvoie à nouveau l'objet racine, ce qui empêche d'autres modifications de mise en page de l'objet chargé (à moins que vous ne puissiez le trouver en utilisant findViewById()). La convention d'appel que vous aimeriez probablement utiliser est donc celle-ci:

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

Pour résoudre les problèmes de mise en page, l' inspecteur de mise en page est fortement recommandé.

Andig
la source
20
Excellente réponse. Je travaille sur Android depuis 3 ans et je compte et j'ai encore quelque chose à apprendre de cela.
Reuben Scratton
Salut, existe-t-il un moyen de faire la même chose avec le code java au lieu de gonfler avec R.layout. parce que je n'ai pas de mise en page. J'ai créé la vue avec du code java et je souhaite ajouter la même vue 300 fois.
Raj
1
@andig: Activityest une sous-classe de Contextet les exemples de réponse sont dans la portée de Activity, donc pour simplifier, j'ai remplacé getBaseContext()par thisas, pour les besoins de cette réponse, c'est équivalent.
Marcin Orlowski
5
container a layout_width et layout_height mis à "match_parent"; puis le commentaire dit "// résultat: layout_height = wrap_content layout_width = match_parent". Est-ce que je manque qc?
Marian Paździoch
1
Merci d'avoir fait la recherche et partagé les résultats! Aussi, je seconde la question de Marian.
LarsH
5

andig est correct qu'une raison courante pour LayoutInflater d'ignorer vos layout_params serait parce qu'une racine n'a pas été spécifiée. Beaucoup de gens pensent que vous pouvez passer null pour root. Ceci est acceptable pour quelques scénarios tels qu'une boîte de dialogue, où vous n'avez pas accès à la racine au moment de la création. Une bonne règle à suivre, cependant, est que si vous avez root, donnez-le à LayoutInflater.

J'ai écrit un article de blog approfondi à ce sujet que vous pouvez consulter ici:

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

seanjfarrell
la source
1
This is acceptable for a few scenarios such as a dialogc'était tout ce dont j'avais besoin
rookieDeveloper
0

je veux ajouter à la réponse principale ci-dessus
j'ai essayé de la suivre mais mon recyclerView a commencé à étirer chaque élément sur un écran que
je devais ajouter la ligne suivante après avoir gonflé pour atteindre l'objectif

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

J'ai déjà ajouté ces paramètres par xml mais cela ne fonctionnait pas correctement
et avec cette ligne tout va bien

Kirguduck
la source