Яка мета тегу <merge> Android у макетах XML?


325

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

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

тоді <include />код в іншому файлі?

Відповіді:


584

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

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

layout1.xml:

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

layout2.xml:

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

що функціонально еквівалентно цій єдиній компоновці:

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

Цей FrameLayout у layout2.xml може бути не корисним. <merge/>допомагає позбутися. Ось як виглядає використання об'єднання (layout1.xml не змінюється):

layout2.xml:

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

Це функціонально еквівалентно цій компоновці:

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

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


17
У цьому прикладі ви можете просто зробити layout2.xml містити просто <TextView />, нічого іншого.
Кару

21
Правда, простий TextView може бути використаний натомість у layout2, однак це було б зовсім іншою справою, а не корисним прикладом у відповіді на це питання.
Дейв

У поєднанні з тегом <include> завжди корисно використовувати тег <merge>.
Аншул

38
@Karu: ти маєш рацію, тег злиття не потрібен у цьому прикладі, але це лише тому, що в layout2 є один елемент. Якщо у layout2 було кілька елементів, ОБОВ'ЯЗКОВО мати кореневий вузол, щоб бути дійсним XML, і тоді тег злиття стане у нагоді.
gMale

3
Тож як би ви вказали, якщо <merge> має вертикальну або горизонтальну орієнтацію? І як ви даєте layout_weight?
ІгорГанапольський

304

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

<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 з файлів include просто скидається у ваш top_level_activityмакет під час візуалізації (майже як #INCLUDEмакрос для C).

Файли, що включають, мають простий макет xnex 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"/>

... і включати2.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>

Ви зберегли один рівень ієрархії, уникайте одного марного вигляду: Ромен Гай вже спить краще.

Ви зараз не щасливіші?


23
Відмінний опис.
RichieHH

4
пояснює дуже чітко, слід обрати як відповідь
лаліт

2
Відмінно, без сумніву, це має бути прийнята відповідь.
gaurav jain

1
щось не зрозумів .. що робити, наприклад, якщо зовнішня LinearLayout є вертикальною, але два текстових огляди в include1.xml повинні були бути горизонтальними? злиття в цьому випадку не врятує їх макет, який я хотів. Що з цим можна зробити?
Йонатан Нір

Злиття @YonatanNir - не те, що потрібно у вашому випадку, однозначно. якщо вам дійсно потрібно згладити ієрархію перегляду, то, можливо, ви можете використовувати RelativeLayoutабо малювати представлення вручну
Абхіджит

19

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

  • <merge> використовується для оптимізації макетів. Він використовується для зменшення зайвих вкладень.
  • коли макет, що містить <merge>тег, додається в інший макет, <merge>вузол видаляється і його дочірній вигляд додається безпосередньо до нового батьківського.

10

Для більш глибокого знання того, що відбувається, я створив наступний приклад. Подивіться на 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 після оновлення коду для використання об'єднання замість 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>

Тут ми бачимо, що зайвий 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-файлі, а ваш власний ViewGroup успадкований від RelativeLayout, то тоді було б два RelativeLayouts, один вкладений в інший?
Скотт Біггс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.