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?
<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.
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.
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?
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?
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.<merge>
est ajoutée à une autre disposition, le nœud <merge>
est supprimé et sa vue enfant est ajoutée directement au nouveau parent.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.
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.
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.
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>