在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.xml
和include2.xml
。
请记住,包含文件中的xml在渲染时简单地转储到top_level_activity
布局中(非常类似于C的#INCLUDE
macros)。
包含文件是简洁的布局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.xml和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>
在这里,膨胀的整个布局文件看起来像这样。
<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被移除。 现在布局检查器工具提供以下布局层次结构。
因此,当您的父级布局可以定位您的子级布局时,总是尝试使用合并 ,或者当您明白在层次结构中将存在冗余视图组时,请使用合并 。