Какова цель тега Android <merge>в макетах XML? - PullRequest
284 голосов
/ 12 января 2012

Я прочитал сообщение Ромена Гая о теге <merge />, но я до сих пор не понимаю, насколько это полезно.Это своего рода замена тега <Frame /> или он используется так:

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

затем <include /> код в другом файле?

Ответы [ 5 ]

528 голосов
/ 19 июня 2012

<merge/> полезен, потому что он может избавиться от ненужных ViewGroups, то есть макетов, которые просто используются, чтобы обернуть другие представления и сами по себе не служат.

Например, если вы хотите <include/> макет из другого файла без слияния, эти два файла могут выглядеть примерно так:

layout1.xml:

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

layout2.xml:

<FrameLayout>
   <TextView />
</FrameLayout>

, который функционально эквивалентен этой единственной компоновке:

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

Этот FrameLayout в layout2.xml может быть бесполезен. <merge/> помогает избавиться от этого. Вот как это выглядит при использовании слияния (layout1.xml не изменяется):

layout2.xml:

<merge>
   <TextView />
</merge>

Это функционально эквивалентно этому макету:

<FrameLayout>
   <TextView />
</FrameLayout>

но поскольку вы используете <include/>, вы можете использовать макет в другом месте. Его не нужно использовать для замены только FrameLayouts - вы можете использовать его для замены любого макета, который не добавляет чего-либо полезного к тому, как ваш вид выглядит / ведет себя.

270 голосов
/ 02 января 2014

Тег включения

Тег <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 макете во время рендеринга (почти как макрос #INCLUDEдля C).

Включаемые файлы представляют собой простой формат 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" />

Видите?Ничего фантастического.Обратите внимание, что вам все равно нужно объявить пространство имен 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-коде все это прозрачно: 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>

Вы сохранили один уровень иерархии, избегайте одногобесполезный взгляд: Ромэн Гай уже спит лучше.

Разве ты не счастливее сейчас?

13 голосов
/ 10 декабря 2013

блазерони уже прояснили, я просто хочу добавить несколько моментов.

  • <merge> используется для оптимизации макетов. Используется для уменьшения ненужных вложений.
  • когда макет, содержащий тег <merge>, добавляется в другой макет, узел <merge> удаляется, а его дочернее представление добавляется непосредственно к новому родителю.
5 голосов
/ 11 октября 2017

Чтобы иметь более глубокие знания о том, что происходит, я создал следующий пример.Просмотрите файлы 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который не служит какой-либо цели и является излишним.Взгляд на макет с помощью инструмента «Инспектор макетов» четко объясняет это.

enter image description here

content_profile.xml после обновления кода для использования слияниявместо ViewGroup, как LinearLayout.

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

Здесь мы видим, что избыточная Viewar Group LinearLayout удалена.Теперь инструмент Layout Inspector предоставляет следующую иерархию макетов.

enter image description here

Поэтому всегда старайтесь использовать merge , когда ваш родительский макетможете расположить дочерние макеты или, если точнее, использовать merge , если вы понимаете, что в иерархии будет избыточная группа представлений.

5 голосов
/ 08 февраля 2015

Другая причина использования слияния заключается в использовании пользовательских групп просмотра в списках или 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>
...