La LayoutInflater.inflate
documentación no es exactamente clara para mí sobre el propósito del attachToRoot
parámetro.
attachToRoot : si la jerarquía inflada debe estar asociada al parámetro raíz? Si es falso, la raíz solo se usa para crear la subclase correcta de LayoutParams para la vista raíz en el XML.
¿Podría alguien explicar con más detalle, específicamente cuál es la vista raíz, y tal vez mostrar un ejemplo de un cambio en el comportamiento entre true
y los false
valores?
android
android-layout
android-view
layout-inflater
Jeff Axelrod
fuente
fuente
Respuestas:
AHORA O NO AHORA
La principal diferencia entre el "tercer" parámetro attachToRoot es verdadero o falso es esta.
verdadero: agregue la vista secundaria al principal AHORA MISMO
falso: agregue la vista secundaria al principal NO AHORA .
Añádelo más tarde. ``
Eso más tarde es cuando usas por ejemplo
parent.addView(childView)
Un error común es que, si el parámetro attachToRoot es falso, la vista secundaria no se agregará a la principal. Incorrecto
En ambos casos, la vista secundaria se agregará a parentView. Es solo cuestión de tiempo .
es equivalente a
UN GRAN NO-NO
Nunca debe pasar attachToRoot como verdadero cuando no es responsable de agregar la vista secundaria a primaria.
Por ejemplo, al agregar un fragmento
si pasa el tercer parámetro como verdadero, obtendrá IllegalStateException debido a este tipo.
Como ya ha agregado el fragmento secundario en onCreateView () por error. Llamar a add le dirá que la vista secundaria ya está agregada a la primaria Por lo tanto, IllegalStateException .
Aquí no es responsable de agregar childView, FragmentManager es responsable. Así que siempre pasa falso en este caso.
NOTA: También he leído que parentView no obtendrá childView touchEvents si attachToRoot es falso. Pero no lo he probado sin embargo.
fuente
FragmentManager
, gracias!Si se establece en verdadero, cuando su diseño esté inflado, se agregará automáticamente a la jerarquía de vistas del ViewGroup especificado en el segundo parámetro como elemento secundario. Por ejemplo, si el parámetro raíz era un
LinearLayout
, su vista inflada se agregará automáticamente como elemento secundario de esa vista.Si se establece en falso, su diseño se inflará pero no se adjuntará a ningún otro diseño (por lo que no se dibujará, recibirá eventos táctiles, etc.).
fuente
false
paraattachToRoot
durante mi Fragmento deonCreateView
. Esto resolvió el problema y sin embargo, la disposición del fragmento es visible y activa, a pesar de su respuesta. ¿Qué está pasando aquí?true
, la vista se adjunta al segundo parámetro, que es elcontainer
, pero luego dices que el fragmento se adjunta automáticamenteonCreateView()
, por lo que entiendo, el tercer parámetro es inútil y debe establecersefalse
¿siempre?onCreateView
. Si infla más diseños en esa vista raíz, o está inflando en un contexto diferente (por ejemplo, en una Actividad), entonces es útil.Parece que hay mucho texto en las respuestas pero no hay código, por eso decidí revivir esta vieja pregunta con un ejemplo de código, en varias respuestas las personas mencionaron:
Lo que eso realmente significa en el código (lo que la mayoría de los programadores entienden) es:
Tenga en cuenta que el código anterior está agregando el diseño
R.layout.child_view
como hijo deMyCustomLayout
debido aattachToRoot
param istrue
y asigna los parámetros de diseño del padre exactamente de la misma manera que si estuviera usandoaddView
programáticamente, o como si hiciera esto en xml:El siguiente código explica el escenario al pasar
attachRoot
comofalse
:En el código anterior, especificó que deseaba
myView
ser su propio objeto raíz y no lo adjunte a ningún padre, más tarde lo agregamos como parte de la vista,LinearLayout
pero por un momento fue una vista independiente (sin padre).Lo mismo sucede con Fragments, puede agregarlos a un grupo ya existente y ser parte de él, o simplemente pasar los parámetros:
Para especificar que será su propia raíz.
fuente
La documentación y las dos respuestas anteriores deberían ser suficientes, solo algunas reflexiones mías.
El
inflate
método se utiliza para inflar archivos de diseño. Con esos diseños inflados, tiene la posibilidad de adjuntarlos directamente a un padreViewGroup
o simplemente inflar la jerarquía de vista desde ese archivo de diseño y trabajar con él fuera de la jerarquía de vista normal.En el primer caso, el
attachToRoot
parámetro tendrá que establecerse entrue
(o simplemente usar elinflate
método que toma un archivo de diseño y una raíz principalViewGroup
(nonull
)). En este caso, laView
devolución es simplemente laViewGroup
que se pasó en el método,ViewGroup
a la que se agregará la jerarquía de vista inflada.Para la segunda opción, se devuelve
View
la raízViewGroup
del archivo de diseño. Si recuerda nuestra última discusión de lainclude-merge
pregunta del par, esta es una de las razones de lamerge
limitación de (cuando un archivo de diseñomerge
se infla raíz, debe proporcionar un padre yattachedToRoot
debe estar configurado entrue
). Si tenía un archivo de diseño con la raíz unamerge
etiqueta yattachedToRoot
se configuró,false
entonces elinflate
método no tendrá nada que devolver, yamerge
que no tiene un equivalente. Además, como dice la documentación, lainflate
versión conattachToRoot
set tofalse
es importante porque puede crear la jerarquía de vistas con la correctaLayoutParams
del padre Esto es importante en algunos casos, más notable con los hijos deAdapterView
, una subclase deViewGroup
, para la cual eladdView()
conjunto de métodos no es compatible. Estoy seguro de que recuerdas haber usado esta línea en elgetView()
método:Esta línea garantiza que el
R.layout.row_layout
archivo inflado tenga el correctoLayoutParams
de laAdapterView
subclase establecida en su raízViewGroup
. Si no haría esto, podría tener algunos problemas con el archivo de diseño si la raíz fuera aRelativeLayout
. ElTableLayout/TableRow
también tienen algún especial e importanteLayoutParams
y usted debe asegurarse de que los puntos de vista en ellas tienen la correctaLayoutParams
.fuente
Yo mismo también estaba confundido acerca de lo que era el verdadero propósito de
attachToRoot
deinflate
método. Después de un poco de estudio de IU, finalmente obtuve la respuesta:padre:
en este caso es el widget / diseño que rodea los objetos de vista que desea inflar usando findViewById ().
attachToRoot:
adjunta las vistas a su elemento primario (las incluye en la jerarquía principal), por lo que cualquier evento táctil que reciban las vistas también se transferirá a la vista principal. Ahora depende de los padres si quieren entretener esos eventos o ignorarlos. si se establece en falso, no se agregan como hijos directos del padre y el padre no recibe ningún evento táctil de las vistas.
Espero que esto aclare la confusión
fuente
Escribí esta respuesta porque, incluso después de pasar por varias páginas de StackOverflow, no pude comprender claramente qué significaba attachToRoot. A continuación se muestra el método inflate () en la clase LayoutInflater.
Eche un vistazo al archivo activity_main.xml , el diseño button.xml y MainActivity.java archivo que creé.
activity_main.xml
button.xml
MainActivity.java
Cuando ejecutamos el código, no veremos el botón en el diseño. Esto se debe a que el diseño de nuestro botón no se agrega al diseño de actividad principal, ya que attachToRoot está establecido en falso.
LinearLayout tiene un método addView (vista de vista) que se puede usar para agregar vistas a LinearLayout. Esto agregará el diseño del botón al diseño de la actividad principal y hará que el botón sea visible cuando ejecute el código.
Eliminemos la línea anterior y veamos qué sucede cuando establecemos attachToRoot como verdadero.
Nuevamente vemos que el diseño del botón es visible. Esto se debe a que attachToRoot adjunta directamente el diseño inflado al elemento primario especificado. Que en este caso es root LinearLayout. Aquí no tenemos que agregar las vistas manualmente como lo hicimos en el caso anterior con el método addView (Vista de vista).
¿Por qué las personas obtienen IllegalStateException al establecer attachToRoot como verdadero para un Fragment?
Esto se debe a que para un fragmento ya ha especificado dónde colocar su diseño de fragmento en su archivo de actividad.
El complemento (int parent, Fragment fragment) agrega el fragmento que tiene su diseño al diseño padre. Si configuramos attachToRoot como verdadero, obtendrá IllegalStateException: el elemento secundario especificado ya tiene un elemento primario. Dado que el diseño de fragmentos ya se ha agregado al diseño primario en el método add ().
Siempre debe pasar false para attachToRoot cuando esté inflando Fragments. El trabajo del FragmentManager es agregar, eliminar y reemplazar Fragmentos.
De vuelta a mi ejemplo. ¿Qué pasa si hacemos las dos cosas?
En la primera línea, LayoutInflater adjunta el diseño del botón al diseño raíz y devuelve un objeto Ver que contiene el mismo diseño del botón. En la segunda línea, agregamos el mismo objeto Ver al diseño raíz principal. Esto da como resultado la misma IllegalStateException que vimos con Fragments (el elemento secundario especificado ya tiene un elemento primario).
Tenga en cuenta que existe otro método inflate () sobrecargado, que establece attachToRoot como verdadero de forma predeterminada.
fuente
Hay mucha confusión sobre este tema debido a la documentación para el método inflate ().
En general, si attachToRoot se establece en verdadero, el archivo de diseño especificado en el primer parámetro se infla y se adjunta al ViewGroup especificado en el segundo parámetro en ese momento. Cuando attachToRoot es falso, el archivo de diseño del primer parámetro se infla y se devuelve como una Vista y cualquier archivo adjunto de Vista ocurre en otro momento.
Esto probablemente no signifique mucho a menos que vea muchos ejemplos. Al llamar a LayoutInflater.inflate () dentro del método onCreateView de un Fragment, querrá pasar false para attachToRoot porque la Actividad asociada con ese Fragment es realmente responsable de agregar la vista de ese Fragment. Si está inflando manualmente y agregando una Vista a otra Vista en algún momento posterior, como con el método addView (), querrá pasar false para attachToRoot porque el archivo adjunto llega en un momento posterior.
Puede leer sobre varios otros ejemplos únicos sobre Diálogos y Vistas personalizadas en una publicación de blog que escribí sobre este mismo tema.
https://www.bignerdranch.com/blog/understanding-androids-layoutinflater-inflate/
fuente
attachToRoot
establecido en verdadero significainflatedView
que se agregará a la jerarquía de la vista principal. Por lo tanto, los usuarios pueden "ver" y detectar eventos táctiles (o cualquier otra operación de IU). De lo contrario, se acaba de crear, no se ha agregado a ninguna jerarquía de vista y, por lo tanto, no se puede ver ni manejar eventos táctiles.Para los desarrolladores de iOS nuevos en Android,
attachToRoot
establecer en verdadero significa que llama a este método:Si ir más lejos usted puede preguntar: ¿Por qué debería pasar vista padre si me puse
attachToRoot
afalse
? Esto se debe a que el elemento raíz en su árbol XML necesita la vista principal para calcular algunos LayoutParams (como match parent).fuente
Cuando define el elemento primario, attachToRoot determina si desea que el inflador realmente lo adjunte al elemento primario o no. En algunos casos esto causa problemas, como en un ListAdapter causará una excepción porque la lista intenta agregar la vista a la lista pero dice que ya está adjunta. En otro caso en el que solo está inflando la vista para agregarla a una Actividad, podría ser útil y ahorrarle una línea de código.
fuente
Por ejemplo tenemos un
ImageView
, aLinearLayout
y aRelativeLayout
. LinearLayout es el hijo de RelativeLayout. Verá la jerarquía.y tenemos un archivo de diseño separado para ImageView
image_view_layout.xml
Adjuntar a la raíz:
setImageResource(R.drawable.np);
de ImageView, deberá encontrarlo mediante la referencia de padre, es decirview.findById()
No adjuntar a la raíz:
view.setImageResource(R.drawable.np);
sin referenciar comofindViewById
. Pero el contenedor se especifica para que ImageView obtenga los LayoutParams del contenedor, por lo que puede decir que la referencia del contenedor es solo para LayoutParams y nada más.fuente
attachToRoot Establecer en verdadero:
Imagine que especificamos un botón en un archivo de diseño XML con su ancho de diseño y altura de diseño establecidos para emparejar_parente.
Ahora queremos agregar mediante programación este botón a un diseño lineal dentro de un fragmento o actividad. Si nuestro LinearLayout ya es una variable miembro, mLinearLayout, simplemente podemos agregar el botón con lo siguiente:
Especificamos que queremos inflar el botón desde su archivo de recursos de diseño; luego le decimos al LayoutInflater que queremos adjuntarlo a mLinearLayout. Se respetan nuestros parámetros de diseño porque sabemos que el botón se agrega a un diseño lineal. El tipo de parámetros de diseño del botón debe ser LinearLayout.LayoutParams.
attachToRoot Establecer en falso (no se requiere para usar falso)
Echemos un vistazo a cuándo desea establecer attachToRoot en falso. En este escenario, la Vista especificada en el primer parámetro de inflate () no está adjunta al ViewGroup en el segundo parámetro en este momento.
Recordemos nuestro ejemplo de botón de antes, donde queremos adjuntar un botón personalizado de un archivo de diseño a mLinearLayout. Todavía podemos adjuntar nuestro botón a mLinearLayout pasando falso para attachToRoot; simplemente lo agregamos manualmente nosotros mismos después.
Estas dos líneas de código son equivalentes a lo que escribimos anteriormente en una línea de código cuando pasamos true para attachToRoot. Al pasar falso, decimos que todavía no queremos adjuntar nuestra Vista al ViewGroup raíz. Estamos diciendo que sucederá en algún otro momento. En este ejemplo, el otro punto en el tiempo es simplemente el método addView () utilizado inmediatamente debajo de la inflación.
El ejemplo falso attachToRoot requiere un poco más de trabajo cuando agregamos manualmente la vista a un grupo de vista.
attachToRoot Establecer en false (se requiere false)
Al inflar y devolver una vista de fragmento en onCreateView (), asegúrese de pasar false para attachToRoot. Si pasa verdadero, obtendrá una IllegalStateException porque el niño especificado ya tiene un padre. Deberías haber especificado dónde se volverá a colocar la vista de tu Fragmento en tu Actividad. El trabajo del FragmentManager es agregar, eliminar y reemplazar Fragmentos.
El contenedor root_viewGroup que contendrá su Fragmento en su Actividad es el parámetro ViewGroup que se le proporciona en onCreateView () en su Fragmento. También es el ViewGroup que pasa a LayoutInflater.inflate (). Sin embargo, el FragmentManager se encargará de adjuntar la Vista de su Fragmento a este ViewGroup. No desea adjuntarlo dos veces. Establezca attachToRoot en falso.
¿Por qué nos dan el ViewGroup padre de nuestro Fragmento en primer lugar si no queremos adjuntarlo en onCreateView ()? ¿Por qué el método inflate () solicita un ViewGroup raíz?
Resulta que incluso cuando no agreguemos de inmediato nuestra Vista recién inflada a su Grupo de vista padre, aún debemos usar los LayoutParams del padre para que la nueva Vista determine su tamaño y posición cada vez que se adjunte.
Enlace: https://youtu.be/1Y0LlmTCOkM?t=409
fuente
Solo compartiendo algunos puntos que encontré mientras trabajaba en este tema,
Además de la respuesta aceptada, quiero algunos puntos que podrían ser de alguna ayuda.
Entonces, cuando utilicé attachToRoot como verdadero, la vista que se devolvió fue de tipo ViewGroup, es decir, la raíz de ViewGroup principal que se pasó como parámetro para el método de inflado (layoutResource, ViewGroup, attachToRoot) , no del tipo de diseño que se pasó sino de attachToRoot como falso obtenemos el tipo de retorno de función del ViewGroup raíz de ese layoutResource .
Dejame explicarte con un ejemplo:
Si tenemos un LinearLayout como diseño de raíz y luego queremos agregar TextView a través de inflar función.
luego, al usar attachToRoot como verdadera función de inflado, devuelve una vista de tipo LinearLayout
mientras se usa attachToRoot como función de inflado falso devuelve una vista de tipo TextView
Espero que este hallazgo sea de alguna ayuda ...
fuente