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.