我已经阅读了Romain Guy在<merge />标签上的帖子,但我仍然不明白它的用处。是对<Frame />标签的某种替换,还是这样使用:

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


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

#1 楼

<merge/>很有用,因为它可以摆脱不需要的ViewGroup,即仅用于包装其他视图且本身无用的布局。例如,如果您要从另一个文件中进行布局而不使用<include/>使用合并,这两个文件可能看起来像这样:

layout1.xml:

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


layout2.xml:
<在功能上等效于此单个布局的




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


layout2.xml中的FrameLayout可能没有用。 <merge/>帮助摆脱它。这是使用合并的样子(layout1.xml不变):

layout2.xml:

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


这在功能上是等效的到此布局:

<merge>
   <TextView />
   <TextView />
</merge>


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

评论


在此示例中,您可以仅使layout2.xml仅包含,而不包含其他任何内容。

–卡鲁
2013年9月12日下午3:37

的确,可以在layout2中使用一个简单的TextView代替,但是那将是完全不同的事情,并且不能作为示例来回答该问题。

–戴夫
13-10-3在14:55

标记结合使用时,始终使用标记很有用。

– Anshul
2013年12月10日13:04

@Karu:您是对的,在此示例中无需合并标签,但这仅是因为layout2中只有一个元素。如果layout2具有多个元素,则它必须具有一个有效XML的根节点,并且这时merge标签才派上用场。

– gMale
2014年2月22日在16:37

那么如何指定是垂直方向还是水平方向?以及如何给出layout_weight?

– IgorGanapolsky
2014年6月10日14:11

#2 楼

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.xmlinclude2.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:必须声明一个布局。让我们选择一个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已经睡得更好了。

您现在不快乐吗?

评论


出色的描述。

– RichieHH
2014年3月16日在0:26

解释很清楚,应该选择答案

–lalitm
2014年5月21日下午5:58

很好,毫无疑问,这应该是公认的答案。

–高拉夫·in那
15年3月17日在9:25

不了解某事..例如,如果外部LinearLayout是垂直的,但是include1.xml中的两个textview应该是水平的呢?在这种情况下,合并不会保存我想要的布局。该怎么办?

–约纳坦·尼尔(Yonatan Nir)
15年7月8日在7:40

显然,@ YonatanNir合并不是您所需要的。如果您确实需要展平视图层次结构,则可以使用RelativeLayout或手动绘制视图

–阿比吉特
15年7月21日在18:30

#3 楼

blazeroni已经说得很清楚了,我只想添加几个要点。



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


#4 楼

为了更深入地了解正在发生的事情,我创建了以下示例。看一下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,它没有任何作用,并且是多余的。通过Layout Inspector工具查看布局可以清楚地说明这一点。

更新代码以使用合并而不是使用诸如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被删除。现在,“布局检查器”工具提供了以下布局层次结构。



因此,当父布局可以放置子布局时,请始终尝试使用合并,或者当您布局子布局时,请更精确地使用合并了解层次结构中将有一个冗余视图组。

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


评论


您是否暗示如果在XML文件中使用了RelativeLayout,并且您的自定义ViewGroup继承自RelativeLayout,那么将有两个RelativeLayouts,一个嵌套在另一个中?

– SMBiggs
19年8月1日在22:45