tag change android android-layout include code-reuse

change - include xml android



¿Cuál es el propósito de la etiqueta<merge> de Android en diseños XML? (6)

He leído la publicación de Romain Guy en la etiqueta <merge /> , pero todavía no entiendo por qué es útil. ¿Es una especie de reemplazo de la etiqueta <Frame /> , o se usa así?

<merge xmlns:android="...."> <LinearLayout ...> . . . </LinearLayout> </merge>

entonces <include /> el código en otro archivo?


La etiqueta de inclusión

La etiqueta <include> permite dividir su diseño en varios archivos: ayuda a manejar una interfaz de usuario compleja o demasiado larga.

Supongamos que divide su diseño complejo utilizando dos archivos de inclusión de la siguiente manera:

top_level_activity.xml :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <!-- First include file --> <include layout="@layout/include1.xml" /> <!-- Second include file --> <include layout="@layout/include2.xml" /> </LinearLayout>

Entonces necesitas escribir include1.xml y include2.xml .

Tenga en cuenta que el xml de los archivos de inclusión simplemente se descarga en el diseño de top_level_activity en el momento de renderizar (muy parecido a la macro #INCLUDE para C).

Los archivos incluidos son xml de diseño de jane llano.

include1.xml :

<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/textView1" android:text="First include" android:textAppearance="?android:attr/textAppearanceMedium"/>

... e include2.xml :

<?xml version="1.0" encoding="utf-8"?> <Button xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/button1" android:text="Button" />

¿Ver? Nada sofisticado. Tenga en cuenta que todavía tiene que declarar el espacio de nombres de Android con xmlns:android="http://schemas.android.com/apk/res/android .

Así que la versión renderizada de top_level_activity.xml es:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <!-- First include file --> <TextView android:id="@+id/textView1" android:text="First include" android:textAppearance="?android:attr/textAppearanceMedium"/> <!-- Second include file --> <Button android:id="@+id/button1" android:text="Button" /> </LinearLayout>

En su código Java, todo esto es transparente: findViewById(R.id.textView1) en su clase de actividad devuelve el widget correcto (incluso si ese widget se declaró en un archivo xml diferente del diseño de la actividad).

Y la guinda en la parte superior: el editor visual maneja la cosa a la perfección. El diseño de nivel superior se representa con el xml incluido.

La trama se complica

Como un archivo de inclusión es un archivo xml de diseño clásico, significa que debe tener un elemento superior. Por lo tanto, en caso de que su archivo deba incluir más de un widget, tendrá que usar un diseño.

Digamos que include1.xml tiene ahora dos TextView : un diseño debe ser declarado. Vamos a elegir un LinearLayout .

include1.xml :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout2" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/textView1" android:text="Second include" android:textAppearance="?android:attr/textAppearanceMedium"/> <TextView android:id="@+id/textView2" android:text="More text" android:textAppearance="?android:attr/textAppearanceMedium"/> </LinearLayout>

El archivo top_level_activity.xml se representará como:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <!-- First include file --> <LinearLayout android:id="@+id/layout2" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/textView1" android:text="Second include" android:textAppearance="?android:attr/textAppearanceMedium"/> <TextView android:id="@+id/textView2" android:text="More text" android:textAppearance="?android:attr/textAppearanceMedium"/> </LinearLayout> <!-- Second include file --> <Button android:id="@+id/button1" android:text="Button" /> </LinearLayout>

¡Pero espera que los dos niveles de LinearLayout sean redundantes !

De hecho, los dos LinearLayout anidados no tienen ningún propósito ya que los dos TextView podrían incluirse en layout1 para exactamente la misma representación .

Entonces, ¿qué podemos hacer?

Ingrese la etiqueta de combinación

La etiqueta <merge> es solo una etiqueta ficticia que proporciona un elemento de nivel superior para tratar este tipo de problemas de redundancia.

Ahora include1.xml se convierte en:

<merge xmlns:android="http://schemas.android.com/apk/res/android"> <TextView android:id="@+id/textView1" android:text="Second include" android:textAppearance="?android:attr/textAppearanceMedium"/> <TextView android:id="@+id/textView2" android:text="More text" android:textAppearance="?android:attr/textAppearanceMedium"/> </merge>

y ahora top_level_activity.xml se representa como:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <!-- First include file --> <TextView android:id="@+id/textView1" android:text="Second include" android:textAppearance="?android:attr/textAppearanceMedium"/> <TextView android:id="@+id/textView2" android:text="More text" android:textAppearance="?android:attr/textAppearanceMedium"/> <!-- Second include file --> <Button android:id="@+id/button1" android:text="Button" /> </LinearLayout>

Guardaste un nivel jerárquico, evita una vista inútil: Romain Guy ya duerme mejor.

¿No eres más feliz ahora?


En palabras simples y precisas,

Cuando un diseño que contiene una etiqueta de combinación se agrega a otro diseño, el nodo de combinación se elimina y sus Vistas secundarias se agregan directamente al nuevo elemento primario.

la etiqueta de combinación es particularmente útil junto con la include tag , que se utiliza para insertar el contenido de un diseño en otro.

Ejemplo

<?xml version=”1.0” encoding=”utf-8”?> <LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android” android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <include android:id="@+id/my_id1" layout="@layout/layout1"/> <include android:id="@+id/my_id2" layout="@layout/layout2"/> </LinearLayout>


Otra razón para usar la combinación es cuando se usan grupos de vistas personalizados en ListViews o GridViews. En lugar de usar el patrón viewHolder en un adaptador de lista, puede usar una vista personalizada. La vista personalizada inflaría un xml cuya raíz es una etiqueta de combinación. Código para el adaptador:

public class GridViewAdapter extends BaseAdapter { // ... typical Adapter class methods @Override public View getView(int position, View convertView, ViewGroup parent) { WallpaperView wallpaperView; if (convertView == null) wallpaperView = new WallpaperView(activity); else wallpaperView = (WallpaperView) convertView; wallpaperView.loadWallpaper(wallpapers.get(position), imageWidth); return wallpaperView; } }

Aquí está el grupo de vista personalizado:

public class WallpaperView extends RelativeLayout { public WallpaperView(Context context) { super(context); init(context); } // ... typical constructors private void init(Context context) { View.inflate(context, R.layout.wallpaper_item, this); imageLoader = AppController.getInstance().getImageLoader(); imagePlaceHolder = (ImageView) findViewById(R.id.imgLoader2); thumbnail = (NetworkImageView) findViewById(R.id.thumbnail2); thumbnail.setScaleType(ImageView.ScaleType.CENTER_CROP); } public void loadWallpaper(Wallpaper wallpaper, int imageWidth) { // ...some logic that sets the views } }

y aquí está el XML:

<merge xmlns:android="http://schemas.android.com/apk/res/android"> <ImageView android:id="@+id/imgLoader" android:layout_width="30dp" android:layout_height="30dp" android:layout_centerInParent="true" android:src="@drawable/ico_loader" /> <com.android.volley.toolbox.NetworkImageView android:id="@+id/thumbnail" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </merge>


Para tener un conocimiento más profundo de lo que está sucediendo, creé el siguiente ejemplo. Eche un vistazo a los archivos activity_main.xml y content_profile.xml .

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <include layout="@layout/content_profile" /> </LinearLayout>

content_profile.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Howdy" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Hi there" /> </LinearLayout>

Aquí, el archivo de diseño completo cuando está inflado se ve así.

<LinearLayout> <LinearLayout> <TextView /> <TextView /> </LinearLayout> </LinearLayout>

Vea que hay un LinearLayout dentro del LinearLayout principal que no sirve para ningún propósito y es redundante. Una mirada al diseño a través de la herramienta Inspector de diseño explica esto claramente.

content_profile.xml después de actualizar el código para usar la combinación en lugar de un ViewGroup como LinearLayout.

<merge xmlns:android="http://schemas.android.com/apk/res/android"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Howdy" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Hi there" /> </merge>

Ahora nuestro diseño se ve así

<LinearLayout> <TextView /> <TextView /> </LinearLayout>

Aquí vemos que se elimina el grupo de vista LinearLayout redundante. Ahora la herramienta Inspector de diseño proporciona la siguiente jerarquía de diseño.

Por lo tanto, siempre trate de usar la combinación cuando su diseño primario pueda ubicar sus diseños secundarios, o más precisamente use la combinación cuando entienda que va a haber un grupo de vista redundante en la jerarquía.


<merge/> es útil porque puede deshacerse de ViewGroups innecesarios, es decir, diseños que simplemente se usan para envolver otras vistas y no sirven para nada.

Por ejemplo, si tuviera que <include/> un diseño de otro archivo sin usar la combinación, los dos archivos podrían tener este aspecto:

layout1.xml:

<FrameLayout> <include layout="@layout/layout2"/> </FrameLayout>

layout2.xml:

<FrameLayout> <TextView /> </FrameLayout>

que es funcionalmente equivalente a este diseño único:

<FrameLayout> <FrameLayout> <TextView /> </FrameLayout> </FrameLayout>

Ese FrameLayout en layout2.xml puede no ser útil. <merge/> ayuda a deshacerse de él. Esto es lo que parece al usar la combinación (layout1.xml no cambia):

layout2.xml:

<merge> <TextView /> </merge>

Esto es funcionalmente equivalente a este diseño:

<FrameLayout> <TextView /> </FrameLayout>

pero como está utilizando <include/> puede reutilizar el diseño en otro lugar. No tiene que ser usado para reemplazar solo FrameLayouts, puede usarlo para reemplazar cualquier diseño que no agregue algo útil a la forma en que se ve o se comporta su vista.


blazeroni ya lo dejó bastante claro, solo quiero agregar algunos puntos.

  • <merge> se utiliza para optimizar diseños. Se utiliza para reducir el anidamiento innecesario.
  • cuando un diseño que contiene la etiqueta <merge> se agrega a otro diseño, el nodo <merge> se elimina y su vista secundaria se agrega directamente al nuevo elemento primario.
  • <merge> etiqueta <merge> es particularmente útil con <include> que se usa para insertar el contenido de otro diseño.