在XML布局中Android的<merge>标签的目的是什么?

我已经阅读了<merge />标签上的Romain Guy的post ,但我仍然不明白它的用处。 它是对<Frame />标签的一种replace,还是像这样使用:

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

然后<include />在另一个文件中的代码?

<merge/>是有用的,因为它可以摆脱不需要的ViewGroups,也就是简单地用来包装其他视图并且自己没有任何用途的布局。

例如,如果您要在不使用合并的情况下从另一个文件中<include/>布局,则这两个文件可能如下所示:

layout1.xml:

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

layout2.xml:

 <FrameLayout> <TextView /> </FrameLayout> 

这在function上等同于这种单一布局:

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

layout2.xml中的FrameLayout可能没有用处。 <merge/>有助于摆脱它。 下面是使用合并(layout1.xml不更改)的样子:

layout2.xml:

 <merge> <TextView /> </merge> 

这在function上等同于这种布局:

 <FrameLayout> <TextView /> </FrameLayout> 

但是由于您正在使用<include/> ,所以可以在其他地方重新使用布局。 它不一定要用来replaceFrameLayouts – 你可以用它来replace任何没有添加有用的视图的方式,你的视图看起来/行为。

包含标签

<include>标签可让您将布局分成多个文件:它有助于处理复杂或超长的用户界面。

假设您使用两个包含文件分割您的复杂布局,如下所示:

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> 

然后你需要编写include1.xmlinclude2.xml

请记住,包含文件中的xml在渲染时简单地转储top_level_activity布局中(非常类似于C的#INCLUDEmacros)。

包含文件是简洁的布局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"/> 

…和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" /> 

看到? 没什么奇特的。 请注意,您仍然必须使用xmlns:android="http://schemas.android.com/apk/res/android声明android命名空间xmlns:android="http://schemas.android.com/apk/res/android

所以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 --> <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> 

在java代码中,所有这些都是透明的:在activity类中的findViewById(R.id.textView1)返回正确的小部件(即使该小部件是在与活动布局不同的xml文件中声明的)。

而顶上的樱桃: 视觉编辑器游泳处理事物。 顶层布局是使用 xml进行渲染的。

情节变厚了

由于包含文件是一个经典的布局xml文件,这意味着它必须有一个顶层元素。 因此,如果您的文件需要包含多个小部件,则必须使用布局。

假设include1.xml现在有两个TextView :一个布局必须被声明。 我们select一个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> 

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

但是等待LinearLayout的两个级别是多余的

实际上,两个嵌套的LinearLayout没有任何用处,因为两个TextView可以被包含在layout1下, 完全相同的渲染

那我们能做什么?

input合并标签

<merge>标签只是一个虚拟标签,它提供了一个顶级元素来处理这种冗余问题。

现在include1.xml变成:

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

现在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 --> <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> 

您保存了一个层次结构级别,避免了一个无用的视图:Romain Guy已经睡好了。

你现在不开心吗?

简而言之,

将包含合并标签的布局添加到另一个布局时,合并节点将被删除,并将其子视图直接添加到新的父级。

合并标签include tag结合使用特别有用,它用于将一个布局的内容插入到另一个布局中。

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

blazeroni已经说得很清楚了,我只想补充几点。

  • <merge>用于优化布局,用于减less不必要的嵌套。
  • 当包含<merge>标签的布局被添加到另一个布局中时, <merge>节点被删除,其子视图直接添加到新的父级。
  • <merge>标签对于用于插入其他布局的内容的<include>特别有用。

使用合并的另一个原因是在ListView或GridView中使用自定义视图组时。 而不是在列表适配器中使用viewHolder模式,您可以使用自定义视图。 自定义视图会夸大其根目录为合并标记的xml。 适配器代码:

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

这里是自定义视图组:

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

这里是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> 

为了更深入地了解发生了什么,我创build了以下示例。 看一下activity_main.xmlcontent_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> 

在这里,膨胀的整个布局文件看起来像这样。

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

看到LinearLayout的父LinearLayout中有一个LinearLayout,它不起任何作用,而且是多余的。 通过Layout Inspector工具查看布局清楚地解释了这一点。

在这里输入图像描述

content_profile.xml更新代码后使用合并,而不是像LinearLayout ViewGroup。

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

现在我们的布局看起来像这样

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

在这里我们看到多余的LinearLayout ViewGroup被移除。 现在布局检查器工具提供以下布局层次结构。

在这里输入图像描述

因此,当您的父级布局可以定位您的子级布局时,总是尝试使用合并 ,或者当您明白在层次结构中将存在冗余视图组时,请使用合并