uso español ejemplo developer dev definicion constraintlayout constraint android android-layout android-constraintlayout viewgroup constraint-layout

android - español - Usando<include> con<merge> en ConstraintLayout



match constraint android (8)

Tengo problemas para usar las etiquetas <include> y <merge> dentro de un ConstraintLayout.

Quiero crear una jerarquía de vista plana (por lo tanto, restricciones) pero aún tengo elementos que son reutilizables. Así que uso <include> en mi diseño y <merge> en los diseños incluidos para evitar tener diseños anidados (especialmente evitando los RestraintLayouts anidados)

Así que escribí esto: diseño de los padres

<android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <include android:id="@+id/review_1" layout="@layout/view_movie_note" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/review_2"/> <include layout="@layout/view_movie_note" android:id="@+id/review_2" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginLeft="7dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@+id/review_1" app:layout_constraintRight_toRightOf="parent" /> </android.support.constraint.ConstraintLayout>

y este view_movie_note:

<merge> <TextView android:id="@+id/note_origin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="15dp" android:layout_marginStart="5dp" app:layout_constraintStart_toStartOf="@+id/cardView2" app:layout_constraintTop_toTopOf="parent" android:layout_marginLeft="5dp" /> <android.support.v7.widget.CardView android:id="@+id/five_star_view_container" android:layout_width="0dp" android:layout_height="52dp" android:layout_marginBottom="8dp" android:layout_marginTop="10dp" android:elevation="3dp" app:cardUseCompatPadding="true" app:contentPaddingTop="22dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHeight_min="52dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/note_origin"> <FiveStarsView android:id="@+id/five_star_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" /> </android.support.v7.widget.CardView> <android.support.v7.widget.CardView android:id="@+id/cardView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" app:cardBackgroundColor="@color/colorPrimary" app:contentPaddingLeft="15dp" app:contentPaddingRight="15dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/note_origin"> <TextView android:id="@+id/grade" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="12sp" /> </android.support.v7.widget.CardView> </merge>

Estoy esperando esto

En su lugar tengo esto

Claramente, las restricciones que pongo en la etiqueta <include> están anuladas por las restricciones en el diseño incluido.

Es este el comportamiento esperado ? En caso afirmativo, ¿cómo se supone que debemos mantener un diseño plano con <include> y ConstraintLayout?


Respuesta corta

El mejor movimiento será reemplazar el bloque <merge> con un ConstraintLayout (anidado) en lugar de usar una estructura de diseño redundante.



Según Daniele Segato (el que puso recompensa al cargo),

ConstraintLayout es excelente, pero no funciona bien con la composición y la separación de responsabilidades de cada pieza.

Eso está mal. ConstraintLayout funciona bien con la reutilización de diseños. Cualquier diseño en el que todas las vistas secundarias se distribuyan de acuerdo con las relaciones entre las vistas de hermanos y el diseño principal, se comporta exactamente de esta manera. Esto es cierto incluso para RelativeLayout .


Entonces, ¿dónde está el problema?

Echemos un vistazo más de cerca a lo que <merge> es.

El doc dice

La etiqueta <merge/> ayuda a eliminar grupos de vistas redundantes en su jerarquía de vistas al incluir un diseño dentro de otro.

Tendrá el mismo efecto que reemplazar el elemento <include> con el contenido del bloque <merge> . En otras palabras, las vistas en el bloque <merge/> se colocan directamente en el diseño principal sin un grupo de vistas intermedio. Por lo tanto, las restricciones del elemento <include> se ignoran por completo.

En este ejemplo particular, las vistas en el diseño incluido se agregan dos veces al padre como la segunda, una encima de otra.


Conclusión

Los archivos de recursos de diseño están destinados a ser utilizados de forma independiente. Para calificar el término reutilizable, no debe depender de su padre (el grupo de vista en el que se agregará en el futuro). Se vería bien si tuvieras que incluir el diseño solo una vez. Pero </merge> tampoco será una buena idea en ese caso porque no puede colocarlo en un diseño diferente en una posición diferente.

Obviamente, las jerarquías de diseño plano tienen mejor rendimiento. Sin embargo, a veces es posible que tengamos que sacrificarlo.


Ajustar las etiquetas de include con las etiquetas ConstraintLayout luego mover los atributos de las etiquetas de include a estas nuevas etiquetas ConstraintLayout :

<android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.constraint.ConstraintLayout android:id="@+id/review_1" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/review_2"> <include layout="@layout/view_movie_note" /> </android.support.constraint.ConstraintLayout> <android.support.constraint.ConstraintLayout android:id="@+id/review_2" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginLeft="7dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@+id/review_1" app:layout_constraintRight_toRightOf="parent"> <include layout="@layout/view_movie_note" /> </android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>


Algunos problemas con su pregunta:

  1. Según el link documentación de Android

También puede anular todos los parámetros de diseño (cualquier atributo de android: layout_ *) de la vista raíz del diseño incluido especificándolos en la etiqueta <include /> Por lo tanto, cualquier restricción que ponga en la etiqueta de inclusión se eliminará.

  1. Cualquier android:id en include NO será anulado si la etiqueta merge se usa en el diseño incluido.

  2. El encadenamiento y la adición de restricciones funcionan en vistas con diferentes ID. Por lo tanto, incluir la misma vista varias veces con el mismo peso no funcionará mediante la etiqueta de inclusión

Dicho esto, puedes copiar y pegar todo

Por lo tanto, no se puede utilizar incluir de esta manera.

Te quedan 3 opciones:

  1. Use algún otro ViewGroup (por ejemplo, LinearLayout y luego restringir el diseño)
  2. Copie y pegue el contenido del diseño de include con diferentes ID de vistas.
  3. Modifique el código ConstraintLayout para que sea compatible con las cadenas de distribución para que todo el diseño incluido se copie horizontalmente.

OMI, la primera opción es mejor si tiene un número pequeño de estos diseños, la segunda opción es mejor si tiene solo un diseño (pregunta en cuestión) y la tercera opción es mejor si tiene un gran número de diseños.


Como solucion

Diseño de los padres

<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.LinearLayoutCompat android:layout_width="match_parent" android:layout_height="wrap_content" android:weightSum="2"> <include android:id="@+id/review_1" layout="@layout/view_movie_note" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/review_2" app:layout_constraintTop_toTopOf="parent" /> <include android:id="@+id/review_2" layout="@layout/view_movie_note" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="7dp" android:layout_weight="1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@+id/review_1" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.v7.widget.LinearLayoutCompat> </android.support.constraint.ConstraintLayout>

view_movie_note

<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/note_origin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="15dp" android:layout_marginLeft="5dp" android:layout_marginStart="5dp" app:layout_constraintStart_toStartOf="@+id/cardView2" app:layout_constraintTop_toTopOf="parent" /> <android.support.v7.widget.CardView android:id="@+id/five_star_view_container" android:layout_width="wrap_content" android:layout_height="52dp" android:layout_marginBottom="8dp" android:layout_marginTop="10dp" android:elevation="3dp" app:cardUseCompatPadding="true" app:contentPaddingTop="22dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHeight_min="52dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/note_origin"> <!--<FiveStarsView--> <!--android:id="@+id/five_star_view"--> <!--android:layout_width="wrap_content"--> <!--android:layout_height="wrap_content"--> <!--android:layout_gravity="center_horizontal" />--> <RatingBar android:id="@+id/ratingBar" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </android.support.v7.widget.CardView> <android.support.v7.widget.CardView android:id="@+id/cardView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" app:cardBackgroundColor="@color/colorPrimary" app:contentPaddingLeft="15dp" app:contentPaddingRight="15dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/note_origin"> <TextView android:id="@+id/grade" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="12sp" /> </android.support.v7.widget.CardView> </android.support.constraint.ConstraintLayout>


Puedes usar FrameLayout para incluir diseños comunes. Prueba esto:

<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@+id/review_1" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/review_2" app:layout_constraintTop_toTopOf="parent"> <include layout="@layout/view_movie_note" android:layout_width="0dp" android:layout_height="0dp" /> </FrameLayout> <FrameLayout android:id="@+id/review_2" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@+id/review_1" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"> <include layout="@layout/view_movie_note" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginLeft="7dp" /> </FrameLayout> </android.support.constraint.ConstraintLayout>

Espero que te ayude.


el archivo view_movie_note.xml debe tener un solo nodo xml en su raíz; de lo contrario, no habrá dos nodos de diseño que puedan alinearse con restricciones (la etiqueta <merge> podría ser inútil). el hecho de tener dos diseños idénticos con resultados idénticos se suma al problema, ya que las restricciones siempre se definen en relación con un resId , que no es único aquí.

los enfoques alternativos serían, a) usar un LinearLayout para distribuir dos elementos horizontalmente, o b) en caso de que incluso haya más nodos secundarios (lo que supongo), es mejor usar CardView s en un GridLayout con dos columnas , dentro de un GridView / RecyclerView .

Un solo CardView como el nodo raíz de tal diseño infantil sería el que menos se alinearía correctamente.

De acuerdo con el resultado esperado, no se requiere un ConstraintLayout para alinear los nodos de manera similar: con GridLayoutManager , incluso se puede ajustar el recuento de columnas según el tamaño de la pantalla. Un StaggeredGridLayoutManager también sería una opción, cuando la altura de los elementos varía.

en principio, siempre es más fácil trabajar con el marco, que trabajar contra el marco.



La documentación de Android dice

La etiqueta <merge /> ayuda a eliminar grupos de vistas redundantes en su jerarquía de vistas al incluir un diseño dentro de otro

y tiene un ejemplo también

Si su diseño principal es un LinearLayout vertical en el que dos vistas consecutivas se pueden reutilizar en varios diseños, entonces el diseño reutilizable en el que coloca las dos vistas requiere su propia vista raíz. Sin embargo, usar otro LinearLayout como la raíz para el diseño reutilizable resultaría en un LinearLayout vertical dentro de un LinearLayout vertical. El LinearLayout anidado no tiene otro propósito real que el de ralentizar el rendimiento de su UI.

También vea esta respuesta , que le hará comprender más la etiqueta merge.

Problema en su diseño

Para el diseño infantil.

Se colocan restricciones en elementos secundarios dentro de <merge etiqueta de <merge . Eso no esta bien Debido a que las restricciones se destruyen en el tiempo de ejecución cuando ambos diseños secundarios se combinan dentro de su diseño principal. (Dígame si puede hacer esto sin incluir etiqueta, ¿funcionarán sus restricciones?)

Para el diseño de los padres

Lo mismo para la etiqueta <include , le está dando restricciones / atributos personalizados a la etiqueta <include , que se perderá, porque <merge etiqueta <merge está unida a la vista raíz, por lo que no puede aplicar atributos personalizados a la etiqueta <include with <merge . Es por eso que la respuesta de Bahman funcionará.

Los atributos en <include etiqueta de <include funcionan cuando tiene un elemento raíz dentro del diseño secundario y no <merge etiqueta de <merge .

Conclusión

Como está claro, no está utilizando <merge e <include , como debería ser. Has entendido lo que hacen <include y <merge tag. Así que úsalos apropiadamente.

Si pides solucion

ConstraintLayout se introdujo para resolver diseños complejos. No aumentar la complejidad. Entonces, cuando puedes hacer esto fácilmente con LinearLayout elegir Constraints .

Disposición de los padres

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <include android:id="@+id/review_1" layout="@layout/view_movie_note" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> <include android:id="@+id/review_2" layout="@layout/view_movie_note" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="7dp" android:layout_weight="1" /> </LinearLayout>

view_movie_note.xml

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView .../> <android.support.v7.widget.CardView ... </android.support.v7.widget.CardView> <android.support.v7.widget.CardView ... </android.support.v7.widget.CardView> </android.support.constraint.ConstraintLayout>

Espero poder hacerte entender bien.