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:
- 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á.
Cualquier
android:id
en include NO será anulado si la etiqueta merge se usa en el diseño incluido.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:
- Use algún otro ViewGroup (por ejemplo, LinearLayout y luego restringir el diseño)
- Copie y pegue el contenido del diseño de
include
con diferentes ID de vistas. - 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
<?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.
merge es una etiqueta y no un ViewGroup, por lo que todos los parámetros pasados al include serán ignorados ... Puede ver este ViewGroup solo con un diseño duplicado, si necesita administrarlo, puede crear un Group ... XML atributos de diseño de combinación a RelativeLayout a través de inflar
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 otroLinearLayout
como la raíz para el diseño reutilizable resultaría en unLinearLayout
vertical dentro de unLinearLayout
vertical. ElLinearLayout
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.