web-dev-qa-db-fra.com

Quel est le but de la balise <merge> d'Android dans les dispositions XML?

J'ai lu message de Romain Guy sur la balise <merge />, mais je ne comprends toujours pas en quoi cela est utile. S'agit-il d'une sorte de remplacement de la balise <Frame /> ou est-il utilisé comme suit:

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

alors <include /> le code dans un autre fichier?

288
cesar

<merge/> est utile car il peut éliminer les ViewGroups inutiles, c'est-à-dire les dispositions simplement utilisées pour envelopper d'autres vues et ne servir à rien.

Par exemple, si vous deviez <include/> une mise en page d'un autre fichier sans utiliser la fusion, les deux fichiers pourraient ressembler à ceci:

layout1.xml:

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

layout2.xml:

<FrameLayout>
   <TextView />
</FrameLayout>

qui est fonctionnellement équivalent à cette disposition unique:

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

Ce FrameLayout dans layout2.xml peut ne pas être utile. <merge/> aide à s'en débarrasser. Voici à quoi ressemble l'utilisation de la fusion (layout1.xml ne change pas):

layout2.xml:

<merge>
   <TextView />
</merge>

Ceci est fonctionnellement équivalent à cette disposition:

<FrameLayout>
   <TextView />
</FrameLayout>

mais puisque vous utilisez <include/>, vous pouvez réutiliser la présentation ailleurs. Il n'est pas nécessaire de l'utiliser pour remplacer uniquement FrameLayouts - vous pouvez l'utiliser pour remplacer toute disposition qui n'ajoute pas quelque chose d'utile à l'aspect/le comportement de votre vue.

533
blazeroni

Le tag d'inclusion

La balise <include> vous permet de diviser votre mise en page en plusieurs fichiers: elle vous aide à traiter avec une interface utilisateur complexe ou trop longue.

Supposons que vous divisiez votre mise en page complexe à l'aide de deux fichiers d'inclusion, comme suit:

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>
_

Ensuite, vous devez écrire _include1.xml_ et _include2.xml_.

Gardez à l'esprit que le xml des fichiers d'inclusion est simplement vidé dans votre mise en page _top_level_activity_ au moment du rendu (à peu près comme la macro _#INCLUDE_ pour C) .

Les fichiers d'inclusion sont de plain jane layout xml.

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"/>
_

... et 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" />
_

Voir? Rien d'extraordinaire. Notez que vous devez toujours déclarer l'espace de noms Android avec _xmlns:Android="http://schemas.Android.com/apk/res/Android_.

Donc rendu version de top_level_activity.xml est:

_<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>
_

Dans votre code Java, tout cela est transparent: findViewById(R.id.textView1) dans votre classe d'activité renvoie le widget correct (même si ce widget a été déclaré dans un fichier xml différent de la présentation de l'activité).

Et la cerise sur le gâteau: l’éditeur visuel s’occupe de tout. La présentation de niveau supérieur est rendue avec le xml inclus.

L'intrigue se corse

Comme un fichier d'inclusion est un fichier XML de mise en page classique, cela signifie qu'il doit avoir un élément supérieur. Ainsi, si votre fichier doit inclure plusieurs widgets, vous devez utiliser une mise en page.

Disons que _include1.xml_ a maintenant deux TextView: une mise en page doit être déclarée. Choisissons une 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>
_

Le top_level_activity.xml sera rendu comme suit:

_<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>
_

Mais attendez que les deux niveaux de LinearLayout soient redondants !

En effet, les deux LinearLayout imbriqués ne servent à rien car les deux TextView pourraient être inclus sous _layout1_ pour exactement le même rendu .

Alors, que pouvons-nous faire?

Entrez le tag de fusion

La balise _<merge>_ est simplement une balise factice qui fournit un élément de niveau supérieur permettant de traiter ce type de problèmes de redondance.

Maintenant include1.xml devient:

_<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>
_

et maintenant top_level_activity.xml est rendu sous la forme:

_<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>
_

Vous avez sauvegardé un niveau hiérarchique, évitez une vue inutile: Romain Guy dort déjà mieux.

N'es-tu pas plus heureux maintenant?

274
Name is carl

blazeroni a déjà été assez clair, je veux juste ajouter quelques points.

  • <merge> est utilisé pour optimiser les présentations. Il permet de réduire les imbrications inutiles.
  • lorsqu'une disposition contenant la balise <merge> est ajoutée à une autre disposition, le nœud <merge> est supprimé et sa vue enfant est ajoutée directement au nouveau parent.
14
Anshul

Pour avoir une connaissance plus approfondie de ce qui se passe, j'ai créé l'exemple suivant. Regardez les fichiers activity_main.xml et 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>

Ici, le fichier de présentation entier une fois gonflé ressemble à ceci.

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

Vérifiez qu'il existe un LinearLayout dans le parent LinearLayout qui ne sert à rien et qui est redondant. Un coup d’œil à la disposition à travers l’outil Inspecteur de disposition explique clairement cela.

enter image description here

content_profile.xml après la mise à jour du code pour utiliser la fusion au lieu d'un ViewGroup tel que 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>

Maintenant, notre mise en page ressemble à ceci

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

Nous voyons ici que le groupe de vues LinearLayout redondant est supprimé. Maintenant, l'outil Inspecteur de disposition donne la hiérarchie de disposition suivante.

enter image description here

Essayez donc toujours d'utiliser fusionner lorsque votre modèle parent peut positionner vos modèles enfants, ou plus précisément d'utiliser fusionner lorsque vous comprenez qu'il y aura un groupe de vues redondant dans la hiérarchie.

7
capt.swag

Une autre raison d'utiliser la fusion est l'utilisation de groupes de vues personnalisés dans ListViews ou GridViews. Au lieu d'utiliser le modèle viewHolder dans un adaptateur de liste, vous pouvez utiliser une vue personnalisée. La vue personnalisée gonflerait un fichier XML dont la racine est une balise de fusion. Code de l'adaptateur:

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;
    }
}

voici le groupe de visualisation personnalisé:

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
    }
}

et voici le 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>
5
mmienko