Android布局中的<merge>标记的目的是什么?</merge>

时间:2012-01-12 12:13:07

标签: android android-layout include code-reuse

我在<merge />标签上看过Romain Guy's post,但我仍然不明白它是如何有用的。它是<Frame />标签的替代品,还是像以下一样使用:

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

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

6 个答案:

答案 0 :(得分:520)

<merge/>非常有用,因为它可以摆脱不需要的ViewGroups,即简单地用于包装其他视图并且本身没有任何用途的布局。

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

layout1.xml:

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

layout2.xml:

<FrameLayout>
   <TextView />
</FrameLayout>

在功能上等同于这个单一布局:

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

layout2.xml中的FrameLayout可能没用。 <merge/>有助于摆脱它。这是使用merge看起来的样子(layout1.xml不会改变):

layout2.xml:

<merge>
   <TextView />
</merge>

这在功能上等同于这种布局:

<FrameLayout>
   <TextView />
</FrameLayout>

但由于您使用的是<include/>,因此可以在其他地方重复使用该布局。它不必用于仅替换FrameLayouts - 您可以使用它来替换任何未添加对视图外观/行为有用的内容的布局。

答案 1 :(得分:268)

包含标记

<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

请记住,在渲染时,top_level_activity布局中的包含文件中的xml只是 dumped (非常类似于C的#INCLUDE宏)。 / p>

包含文件是普通jane布局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:必须声明布局。我们选择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可以包含在完全相同的渲染中。

那我们该怎么办?

输入合并标记

<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已经睡得好了。

你现在不开心吗?

答案 2 :(得分:13)

blazeroni 已经很明确了,我只是想补充几点。

  • <merge>用于优化布局。它用于减少不必要的嵌套。
  • 当包含<merge>标记的布局添加到另一个布局中时,<merge>节点将被删除,其子视图将直接添加到新父节点。

答案 3 :(得分:5)

使用合并的另一个原因是在ListViews或GridViews中使用自定义视图组。您可以使用自定义视图,而不是在列表适配器中使用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>

答案 4 :(得分:5)

为了更深入地了解发生了什么,我创建了以下示例。查看 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,它不能用于任何目的并且是多余的。通过Layout Inspector工具查看布局清楚地解释了这一点。

enter image description here

更新代码以使用合并而不是像LinearLayout这样的ViewGroup之后,

content_profile.xml

<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已被删除。现在,布局检查器工具提供以下布局层次结构。

enter image description here

因此,当您的父布局可以定位您的子布局时,总是尝试使用 merge ,或者当您了解将要存在时,更准确地使用 merge 层次结构中的冗余视图组。

答案 5 :(得分:0)

根据 android 官方文档,如果不提供任何 SELECT @t FROM ( SELECT @t:=0 limit 10000000 ) T WHERE @t IS NOT NULL merge 等,您必须仅使用 FrameLayout 代替 padding

引用:

<块引用>

合并根框架 - 如果 FrameLayout 是布局的根并且 不提供背景或填充等,它可以用合并替换 标签效率稍高一些。

Docs link