我读过Romain Guy关于<merge />标签的帖子,但我仍然不明白它有什么用。它是<Frame />标签的一种替代,还是像这样使用:
<merge xmlns:android="....">
<LinearLayout ...>
.
.
.
</LinearLayout>
</merge>
然后<include />代码在另一个文件?
我读过Romain Guy关于<merge />标签的帖子,但我仍然不明白它有什么用。它是<Frame />标签的一种替代,还是像这样使用:
<merge xmlns:android="....">
<LinearLayout ...>
.
.
.
</LinearLayout>
</merge>
然后<include />代码在另一个文件?
当前回答
<merge/>是有用的,因为它可以摆脱不需要的viewgroup,即布局只是用来包装其他视图,本身没有任何用途。
例如,如果你要<include/>一个布局从另一个文件没有使用合并,这两个文件可能看起来像这样:
layout1.xml:
<FrameLayout>
<include layout="@layout/layout2"/>
</FrameLayout>
layout2.xml:
<FrameLayout>
<TextView />
<TextView />
</FrameLayout>
这在功能上等同于这个单一的布局:
<FrameLayout>
<FrameLayout>
<TextView />
<TextView />
</FrameLayout>
</FrameLayout>
layout2.xml中的FrameLayout可能没有用处。<merge/>帮助摆脱它。下面是使用merge (layout1.xml没有改变)的样子:
layout2.xml:
<merge>
<TextView />
<TextView />
</merge>
这在功能上等同于下面的布局:
<FrameLayout>
<TextView />
<TextView />
</FrameLayout>
但是由于您使用的是<include/>,您可以在其他地方重用该布局。它不需要只用来替换framamelayouts -你可以用它来替换任何没有为视图的外观/行为添加有用内容的布局。
其他回答
include标签
<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宏)。
包含文件是简单的简布局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名称空间。
所以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代码中,所有这些都是透明的:活动类中的findViewById(R.id.textView1)返回正确的小部件(即使该小部件是在与活动布局不同的xml文件中声明的)。
而锦上添花的是:视觉编辑器处理起来非常流畅。包含xml的顶级布局被呈现。
剧情越来越复杂
由于包含文件是一个经典的布局xml文件,这意味着它必须有一个顶部元素。 因此,如果您的文件需要包含多个小部件,则必须使用布局。
让我们说include1.xml现在有两个TextView:一个布局必须声明。让我们选择一个线性布局。
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下,以实现完全相同的呈现。
那么我们能做什么呢?
输入merge标签
<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已经睡得更好了。
你现在不是更快乐了吗?
<merge/>是有用的,因为它可以摆脱不需要的viewgroup,即布局只是用来包装其他视图,本身没有任何用途。
例如,如果你要<include/>一个布局从另一个文件没有使用合并,这两个文件可能看起来像这样:
layout1.xml:
<FrameLayout>
<include layout="@layout/layout2"/>
</FrameLayout>
layout2.xml:
<FrameLayout>
<TextView />
<TextView />
</FrameLayout>
这在功能上等同于这个单一的布局:
<FrameLayout>
<FrameLayout>
<TextView />
<TextView />
</FrameLayout>
</FrameLayout>
layout2.xml中的FrameLayout可能没有用处。<merge/>帮助摆脱它。下面是使用merge (layout1.xml没有改变)的样子:
layout2.xml:
<merge>
<TextView />
<TextView />
</merge>
这在功能上等同于下面的布局:
<FrameLayout>
<TextView />
<TextView />
</FrameLayout>
但是由于您使用的是<include/>,您可以在其他地方重用该布局。它不需要只用来替换framamelayouts -你可以用它来替换任何没有为视图的外观/行为添加有用内容的布局。
使用merge的另一个原因是在ListViews或gridview中使用自定义视图组。您可以使用自定义视图,而不是在列表适配器中使用viewHolder模式。自定义视图将膨胀根为merge标记的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>
blazeroni已经说得很清楚了,我只想补充几点。
<merge>用于优化布局。它用于减少不必要的嵌套。 当包含<merge>标签的布局被添加到另一个布局中时,<merge>节点将被移除,它的子视图将直接添加到新的父视图中。
为了更深入地了解正在发生的事情,我创建了以下示例。看一下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,它没有任何用途,是多余的。通过布局检查器工具查看布局清楚地解释了这一点。
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被删除了。现在布局检查器工具给出了如下的布局层次结构。
当你的父布局可以定位你的子布局时,总是尝试使用归并,或者更准确地说,当你知道层次结构中会有多余的视图组时,使用归并。