La LayoutInflater.inflate
documentation n'est pas exactement claire pour moi sur l'objectif du attachToRoot
paramètre.
attachToRoot : si la hiérarchie gonflée doit être attachée au paramètre racine? Si faux, root est uniquement utilisé pour créer la sous-classe correcte de LayoutParams pour la vue racine dans le XML.
Quelqu'un pourrait-il expliquer plus en détail, en particulier la vue racine, et peut-être montrer un exemple de changement de comportement entre les valeurs true
et false
?
android
android-layout
android-view
layout-inflater
Jeff Axelrod
la source
la source
Réponses:
MAINTENANT OU PAS MAINTENANT
La principale différence entre le "troisième" paramètre attachToRoot étant vrai ou faux est la suivante.
true: ajoutez la vue enfant au parent RIGHT NOW
false: ajoutez la vue enfant au parent NOT NOW .
Ajoutez-le plus tard. "
C'est plus tard lorsque vous utilisez par exemple
parent.addView(childView)
Une idée fausse courante est que si le paramètre attachToRoot est faux, la vue enfant ne sera pas ajoutée au parent. FAUX
Dans les deux cas, la vue enfant sera ajoutée à parentView. Ce n'est qu'une question de temps .
est équivalent à
A BIG NO-NO
Vous ne devez jamais transmettre attachToRoot comme true lorsque vous n'êtes pas responsable de l'ajout de la vue enfant au parent.
Par exemple, lors de l'ajout d'un fragment
si vous passez le troisième paramètre comme vrai, vous obtiendrez IllegalStateException à cause de ce type.
Puisque vous avez déjà ajouté le fragment enfant dans onCreateView () par erreur. L'appel à add vous indiquera que la vue enfant est déjà ajoutée au parent, d'où IllegalStateException .
Ici, vous n'êtes pas responsable de l'ajout de childView, FragmentManager est responsable. Donc, passez toujours faux dans ce cas.
REMARQUE: j'ai également lu que parentView n'obtiendra pas childView touchEvents si attachToRoot est faux. Mais je ne l'ai pas testé cependant.
la source
FragmentManager
, merci!Si la valeur est true, lorsque votre mise en page est gonflée, elle sera automatiquement ajoutée à la hiérarchie de vues du ViewGroup spécifié dans le 2e paramètre en tant qu'enfant. Par exemple, si le paramètre racine était un
LinearLayout
votre vue gonflée sera automatiquement ajoutée en tant qu'enfant de cette vue.S'il est défini sur false, votre mise en page sera gonflée mais ne sera attachée à aucune autre mise en page (elle ne sera donc pas dessinée, ne recevra pas d'événements tactiles, etc.).
la source
false
pourattachToRoot
pendant mon de FragmentonCreateView
. Cela a résolu le problème et pourtant la mise en page du fragment est visible et active, en dépit de votre réponse. Qu'est - ce qui se passe ici?true
, la vue est attachée au 2ème paramètre qui est lecontainer
, mais vous dites ensuite que le fragment est automatiquement attaché à partironCreateView()
, donc à ma connaissance, le troisième paramètre est inutile et devrait être définifalse
toujours?onCreateView
. Si vous gonflez d'autres mises en page dans cette vue racine, ou si vous gonflez dans un contexte différent (par exemple dans une activité), cela est utile.On dirait beaucoup de texte dans les réponses mais pas de code, c'est pourquoi j'ai décidé de faire revivre cette vieille question avec un exemple de code, dans plusieurs réponses les gens ont mentionné:
Ce que cela signifie réellement dans le code (ce que la plupart des programmeurs comprennent) est:
Notez que le code précédent ajoute la mise
R.layout.child_view
en page en tant qu'enfant àMyCustomLayout
cause deattachToRoot
param istrue
et affecte les paramètres de mise en page du parent exactement de la même manière que si j'utilisais paraddView
programme, ou comme si je faisais cela en xml:Le code suivant explique le scénario lors du passage en
attachRoot
tant quefalse
:Dans le code précédent, vous spécifiez que vous vouliez
myView
être son propre objet racine et ne l'attachez à aucun parent, nous l'avons ajouté plus tard dans le cadre duLinearLayout
mais pour un moment, il s'agissait d'une vue autonome (pas de parent).La même chose se produit avec les fragments, vous pouvez les ajouter à un groupe déjà existant et en faire partie, ou simplement passer les paramètres:
Pour spécifier que ce sera sa propre racine.
la source
La documentation et les deux réponses précédentes devraient suffire, juste quelques réflexions de ma part.
La
inflate
méthode est utilisée pour gonfler les fichiers de mise en page. Avec ces dispositions gonflées, vous devez avoir la possibilité de les attacher directement à un parentViewGroup
ou simplement de gonfler la hiérarchie de vues à partir de ce fichier de disposition et de travailler avec elle en dehors de la hiérarchie de vues normale.Dans le premier cas, le
attachToRoot
paramètre devra être défini surtrue
(ou beaucoup plus simple, utilisez lainflate
méthode qui prend un fichier de mise en page et une racine parentViewGroup
(nonnull
)). Dans ce cas, leView
retour est simplement celuiViewGroup
qui a été passé dans la méthode, leViewGroup
à laquelle la hiérarchie de vue gonflée sera ajoutée.Pour la deuxième option, le retour
View
est la racineViewGroup
du fichier de mise en page. Si vous vous souvenez de notre dernière discussion de lainclude-merge
question des paires, c'est l'une des raisons de lamerge
limitation de (quand un fichier de mise en page avecmerge
comme racine est gonflé, vous devez fournir un parent etattachedToRoot
être défini surtrue
). Si vous aviez un fichier de mise en page avec la racine unemerge
balise et que vous l'aviezattachedToRoot
défini,false
lainflate
méthode n'aura rien à retourner car ellemerge
n'a pas d'équivalent. De plus, comme le dit la documentation, lainflate
version avecattachToRoot
set tofalse
est importante car vous pouvez créer la hiérarchie des vues avec la bonneLayoutParams
du parent. Ceci est important dans certains cas, surtout avec les enfants deAdapterView
, une sous-classe deViewGroup
, pour laquelle lesaddView()
l'ensemble de méthodes n'est pas pris en charge. Je suis sûr que vous vous souvenez d'avoir utilisé cette ligne dans lagetView()
méthode:Cette ligne garantit que le
R.layout.row_layout
fichier gonflé est correct àLayoutParams
partir de laAdapterView
sous - classe définie à sa racineViewGroup
. Si vous ne le faites pas, vous pourriez avoir des problèmes avec le fichier de mise en page si la racine était aRelativeLayout
. IlsTableLayout/TableRow
ont également certains spéciaux et importantsLayoutParams
et vous devez vous assurer que les vues en eux sont correctesLayoutParams
.la source
Je me suis aussi confus au sujet de ce qui était le but réel de
attachToRoot
dans lainflate
méthode. Après un peu d'étude de l'interface utilisateur, j'ai finalement obtenu la réponse:parent:
dans ce cas, c'est le widget / la présentation qui entoure les objets de vue que vous souhaitez gonfler à l'aide de findViewById ().
attachToRoot:
attache les vues à leur parent (les inclut dans la hiérarchie parent), de sorte que tout événement tactile que les vues reçoivent sera également transféré vers la vue parent. Maintenant, c'est au parent de décider s'il veut divertir ces événements ou les ignorer. s'ils sont définis sur false, ils ne sont pas ajoutés en tant qu'enfants directs du parent et le parent ne reçoit aucun événement tactile des vues.
J'espère que cela efface la confusion
la source
J'ai écrit cette réponse parce que même après avoir parcouru plusieurs pages StackOverflow, je n'ai pas pu comprendre clairement ce que signifiait attachToRoot. Vous trouverez ci-dessous la méthode inflate () dans la classe LayoutInflater.
Jetez un oeil à activity_main.xml fichier, button.xml mise en page et le MainActivity.java fichier que j'ai créé.
activity_main.xml
button.xml
MainActivity.java
Lorsque nous exécutons le code, nous ne voyons pas le bouton dans la présentation. Cela est dû au fait que la disposition de nos boutons n'est pas ajoutée à la disposition principale de l'activité car attachToRoot est défini sur false.
LinearLayout possède une méthode addView (View view) qui peut être utilisée pour ajouter des vues à LinearLayout. Cela ajoutera la disposition des boutons à la disposition principale de l'activité et rendra le bouton visible lorsque vous exécuterez le code.
Supprimons la ligne précédente et voyons ce qui se passe lorsque nous définissons attachToRoot sur true.
Encore une fois, nous voyons que la disposition des boutons est visible. En effet, attachToRoot attache directement la disposition gonflée au parent spécifié. Qui dans ce cas est root LinearLayout. Ici, nous n'avons pas à ajouter les vues manuellement comme nous l'avons fait dans le cas précédent avec la méthode addView (View view).
Pourquoi les gens obtiennent-ils IllegalStateException lorsqu'ils définissent attachToRoot comme true pour un fragment.
En effet, pour un fragment, vous avez déjà spécifié où placer la disposition de votre fragment dans votre fichier d'activité.
L' ajout (int parent, Fragment fragment) ajoute le fragment qui a sa disposition à la disposition parent. Si nous définissons attachToRoot sur true, vous obtiendrez IllegalStateException: l'enfant spécifié a déjà un parent. Puisque la disposition des fragments est déjà ajoutée à la disposition parent dans la méthode add ().
Vous devez toujours passer false pour attachToRoot lorsque vous gonflez des fragments. Le travail du FragmentManager consiste à ajouter, supprimer et remplacer des fragments.
Revenons à mon exemple. Et si nous faisons les deux.
Dans la première ligne, LayoutInflater attache la disposition des boutons à la disposition racine et renvoie un objet View qui contient la même disposition des boutons. Dans la deuxième ligne, nous ajoutons le même objet View à la disposition racine parent. Il en résulte la même exception IllegalStateException que nous avons vue avec les fragments (l'enfant spécifié a déjà un parent).
Gardez à l'esprit qu'il existe une autre méthode inflate () surchargée, qui définit attachToRoot comme true par défaut.
la source
Il y a beaucoup de confusion sur ce sujet en raison de la documentation de la méthode inflate ().
En général, si attachToRoot est défini sur true, le fichier de disposition spécifié dans le premier paramètre est gonflé et attaché au ViewGroup spécifié dans le deuxième paramètre à ce moment. Lorsque attachToRoot est faux, le fichier de disposition du premier paramètre est gonflé et renvoyé en tant que vue et toute pièce jointe de vue se produit à un autre moment.
Cela ne signifie probablement pas grand-chose, sauf si vous voyez beaucoup d'exemples. Lorsque vous appelez LayoutInflater.inflate () à l'intérieur de la méthode onCreateView d'un fragment, vous voudrez passer false pour attachToRoot car l'activité associée à ce fragment est en fait responsable de l'ajout de la vue de ce fragment. Si vous gonflez et ajoutez manuellement une vue à une autre vue ultérieurement, comme avec la méthode addView (), vous souhaiterez passer false pour attachToRoot car la pièce jointe arrive à un moment ultérieur.
Vous pouvez lire plusieurs autres exemples uniques concernant les dialogues et les vues personnalisées sur un article de blog que j'ai écrit sur ce sujet.
https://www.bignerdranch.com/blog/understanding-androids-layoutinflater-inflate/
la source
attachToRoot
défini sur true signifie que leinflatedView
sera ajouté à la hiérarchie de la vue parent. Ainsi, les utilisateurs peuvent éventuellement "voir" et détecter des événements tactiles (ou toute autre opération d'interface utilisateur). Sinon, il vient d'être créé, n'a été ajouté à aucune hiérarchie de vue et ne peut donc pas être vu ou gérer les événements tactiles.Pour les développeurs iOS nouveaux sur Android,
attachToRoot
la valeur true signifie que vous appelez cette méthode:Si vous allez plus loin, vous pourriez vous demander: pourquoi devrais-je passer la vue des parents si je mets
attachToRoot
àfalse
? C'est parce que l'élément racine de votre arborescence XML a besoin de la vue parent pour calculer certains LayoutParams (comme match parent).la source
Lorsque vous définissez le parent, attachToRoot détermine si vous souhaitez que le gonfleur l'attache réellement au parent ou non. Dans certains cas, cela provoque des problèmes, comme dans un ListAdapter, il provoquera une exception car la liste essaie d'ajouter la vue à la liste mais elle dit qu'elle est déjà attachée. Dans d'autres cas où vous gonflez simplement la vue vous-même pour l'ajouter à une activité, cela pourrait être pratique et vous faire économiser une ligne de code.
la source
Par exemple, nous avons un
ImageView
, unLinearLayout
et unRelativeLayout
. LinearLayout est l'enfant de RelativeLayout. la hiérarchie des vues sera.et nous avons un fichier de mise en page distinct pour ImageView
image_view_layout.xml
Attacher à la racine:
setImageResource(R.drawable.np);
ImageView, vous devrez le trouver par la référence du parent, c'est-à-direview.findById()
Ne pas attacher à la racine:
view.setImageResource(R.drawable.np);
sans arbitrer commefindViewById
. Mais le conteneur est spécifié afin que ImageView obtienne les LayoutParams du conteneur afin que vous puissiez dire que la référence du conteneur est juste pour LayoutParams rien d'autre.la source
attachToRoot Définissez sur true:
Imaginez que nous ayons spécifié un bouton dans un fichier de mise en page XML avec sa largeur et sa hauteur de mise en page définies sur match_parent.
Nous voulons maintenant ajouter par programme ce bouton à un LinearLayout à l'intérieur d'un fragment ou d'une activité. Si notre LinearLayout est déjà une variable membre, mLinearLayout, nous pouvons simplement ajouter le bouton avec ce qui suit:
Nous avons spécifié que nous voulions gonfler le bouton à partir de son fichier de ressources de mise en page; nous indiquons ensuite au LayoutInflater que nous voulons le joindre à mLinearLayout. Nos paramètres de mise en page sont respectés car nous savons que le bouton est ajouté à un LinearLayout. Le type de paramètres de disposition du bouton doit être LinearLayout.LayoutParams.
attachToRoot Définissez sur false (non requis pour utiliser false)
Jetons un coup d'œil au moment où vous souhaitez définir attachToRoot sur false. Dans ce scénario, la vue spécifiée dans le premier paramètre de inflate () n'est pas attachée au ViewGroup dans le deuxième paramètre à ce stade.
Rappelons notre exemple de bouton précédent, où nous voulons attacher un bouton personnalisé d'un fichier de disposition à mLinearLayout. Nous pouvons toujours attacher notre bouton à mLinearLayout en passant false pour attachToRoot - nous l'ajoutons manuellement nous-mêmes par la suite.
Ces deux lignes de code sont équivalentes à ce que nous avons écrit plus tôt dans une seule ligne de code lorsque nous avons passé true pour attachToRoot. En passant false, nous disons que nous ne voulons pas encore attacher notre vue au ViewGroup racine. Nous disons que cela se produira à un autre moment. Dans cet exemple, l'autre moment est simplement la méthode addView () utilisée immédiatement en dessous de l'inflation.
L'exemple false attachToRoot nécessite un peu plus de travail lorsque nous ajoutons manuellement la vue à un ViewGroup.
attachToRoot Défini sur false (false est obligatoire)
Lorsque vous gonflez et renvoyez la vue d'un fragment dans onCreateView (), assurez-vous de passer false pour attachToRoot. Si vous transmettez true, vous obtiendrez une exception IllegalStateException car l'enfant spécifié a déjà un parent. Vous devriez avoir spécifié où la vue de votre fragment sera replacée dans votre activité. Le travail du FragmentManager consiste à ajouter, supprimer et remplacer des fragments.
Le conteneur root_viewGroup qui contiendra votre fragment dans votre activité est le paramètre ViewGroup qui vous est donné dans onCreateView () dans votre fragment. C'est également le ViewGroup que vous passez dans LayoutInflater.inflate (). Le FragmentManager gérera cependant la liaison de la vue de votre fragment à ce groupe de vues. Vous ne voulez pas le joindre deux fois. Définissez attachToRoot sur false.
Pourquoi nous donne-t-on en premier lieu le ViewGroup parent de notre fragment si nous ne voulons pas le joindre dans onCreateView ()? Pourquoi la méthode inflate () demande-t-elle un ViewGroup racine?
Il s'avère que même lorsque nous n'ajoutons pas immédiatement notre nouvelle vue gonflée à son ViewGroup parent, nous devons toujours utiliser les LayoutParams du parent afin que la nouvelle vue détermine sa taille et sa position chaque fois qu'elle est finalement attachée.
Lien: https://youtu.be/1Y0LlmTCOkM?t=409
la source
Je partage juste quelques points que j'ai rencontrés en travaillant sur ce sujet,
En plus de la réponse acceptée, je voudrais quelques points qui pourraient être utiles.
Ainsi, lorsque j'ai utilisé attachToRoot comme vrai, la vue qui a été renvoyée était de type ViewGroup, c'est-à-dire le ViewGroup racine du parent qui a été passé en paramètre pour la méthode gonfler (layoutResource, ViewGroup, attachToRoot) , pas de type la mise en page qui a été transmise mais sur attachToRoot comme false, nous obtenons le type de retour de fonction du ViewGroup racine de ce layoutResource .
Je m'explique avec un exemple:
Si nous avons un LinearLayout comme disposition racine et que nous voulons ensuite y ajouter TextView via la fonction gonfler .
puis en utilisant attachToRoot comme véritable fonction de gonflement retourne une vue de type LinearLayout
lors de l'utilisation de attachToRoot comme fausse fonction de gonflage renvoie une vue de type TextView
J'espère que cette découverte vous sera utile ...
la source