Как заставить RelativeLayout работать со слиянием и включением? - PullRequest
113 голосов
/ 23 февраля 2010

Я уже несколько дней пытаюсь сделать свои макеты более эффективными, конвертируя из нескольких вложенных LinearLayouts в один RelativeLayout, и столкнулся с несколькими проблемами, которые мне не удалось найти. Обходной путь для ...

Я искал группу новичков Android и этот сайт и не смог найти ничего, что помогло бы мне решить проблему.

Я прочитал в одном из блогов, что вы можете комбинировать макеты со слиянием и включать теги. Итак, у меня есть основной файл макета с корневым элементом RelativeLayout. Внутри этого у меня есть 5 тегов, которые ссылаются на 5 различных файлов макета XML, каждый из которых имеет элемент слияния для корня (все мои файлы слияния одинаковы, за исключением идентификаторов в них).

У меня две проблемы, которые я объясню после публикации упрощенной версии кода моего макета:

Пример основного файла макета:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/translucent_gray" >

    <include 
        android:id="@+id/running_gallery_layout_id"
        layout="@layout/running_gallery_layout" />

    <include 
        android:id="@+id/recent_gallery_layout_id" 
        layout="@layout/recent_gallery_layout"
        android:layout_below="@id/running_gallery_layout_id" />

    <include
        android:id="@+id/service_gallery_layout_id"
        layout="@layout/service_gallery_layout"
        android:layout_below="@id/recent_gallery_layout_id" />

    <include
        android:id="@+id/process_gallery_layout_id"
        layout="@layout/process_gallery_layout"
        android:layout_below="@id/service_gallery_layout_id" />

</RelativeLayout>

Образец включенного файла слияния:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <TextView 
        style="@style/TitleText"
        android:id="@+id/service_gallery_title_text_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="left"
        android:text="@string/service_title" />

    <Gallery
        android:id="@+id/service_gallery_id"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_below="@id/service_gallery_title_text_id" />

    <TextView 
        style="@style/SubTitleText"
        android:id="@+id/service_gallery_current_text_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/service_gallery_title_text_id"
        android:layout_above="@id/service_gallery_id" />
</merge>

У меня две проблемы:

1) Атрибуты android:layout_* игнорируются при использовании в теге include, и все объединенные макеты отображаются друг над другом. Согласно этому сообщению (http://developer.android.com/resources/articles/layout-tricks-reuse.html) "любой атрибут android:layout_* может использоваться с тегом <include />"

2) Так как я не мог заставить это работать, я решил попробовать добавить атрибут android:layout_below к первому элементу TextView в каждом файле макета слияния, что означает, что каждый файл слияния будет ссылаться на идентификатор из другого макета слияния файл ... По большей части это на самом деле работает, и мой макет выглядит хорошо. Тем не менее, я получаю сообщение об ошибке в одном из атрибутов android:layout_below о том, что он не может найти указанный мной идентификатор. Я дважды и трижды проверил идентификаторы, чтобы убедиться, что они верны. Самое странное, что я использовал функцию AutoFill, чтобы поставить идентификатор в атрибуте.

Если у кого-то есть какие-либо предложения или обходные пути, я буду более чем рад их опробовать. Кроме того, если кто-нибудь может придумать, как мне иметь один файл макета слияния xml вместо 5, это было бы очень полезно. Я не мог найти способ сделать это, потому что мне нужно иметь доступ к каждому элементу в файлах макета слияния во время выполнения ...

Ответы [ 7 ]

211 голосов
/ 19 июня 2011

Существует проблема с тегом включения. Проверить: https://issuetracker.google.com/issues/36908001

Чтобы исправить это, убедитесь, что вы включили ОБА layout_width и layout_height при включении, иначе все будет проигнорировано.

33 голосов
/ 31 марта 2010

См. Более высоко оцененный ответ ниже. Шахта крайне устарела


я могу решить одну проблему Джастин поднял: неспособность RelativeLayout управлять позицией включения (по крайней мере, в этом простом случае на эмуляторе 1.6)

CommonsWare предлагает обернуть включаемые элементы в уникальный родительский контейнер, но делает это для облегчения адресации и определения области видимости с одинаково именованными представлениями в Джастин включает в себя

Каждый должен был бы иметь уникальный родительский контейнер, и вы бы вызовите findViewById () для этого контейнера (ViewGroup), а не на Активность.

Фактически, вы также должны сделать это , чтобы заставить RelativeLayout вести себя, как ожидалось:

Это работает ( нижний колонтитул хорошо расположен):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" android:layout_height="fill_parent">
    <include android:id="@+id/header" layout="@layout/header"
        android:layout_alignParentTop="true" />
    <WebView android:id="@+id/webView" android:layout_below="@id/header"
        android:background="#77CC0000" android:layout_height="wrap_content"
        android:layout_width="fill_parent" android:focusable="false" />
    <LinearLayout android:layout_alignParentBottom="true"
        android:layout_height="wrap_content" android:layout_width="fill_parent">
        <include android:id="@+id/footer" layout="@layout/footer" />
    </LinearLayout>
</RelativeLayout>

Это не так ( нижний колонтитул плавает в верхней части экрана):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" android:layout_height="fill_parent">
    <include android:id="@+id/header" layout="@layout/header"
        android:layout_alignParentTop="true" />
    <WebView android:id="@+id/webView" android:layout_below="@id/header"
        android:background="#77CC0000" android:layout_height="wrap_content"
        android:layout_width="fill_parent" android:focusable="false" />
    <include android:id="@+id/footer" layout="@layout/footer"
        android:layout_alignParentBottom="true" />
</RelativeLayout>

Пустой нижний колонтитул include не будет выравниваться по низу родительского элемента без окружающего LinearLayout .. Я бы не назвал это ожидаемое поведение.

Кроме того, кажется, что WebView прекрасно прикрепляется к заголовку по идентификатору, но я считаю, что это иллюзия, поскольку он просто течет ниже заголовка по вертикали. Я также попытался установить кнопку прямо над включением нижнего колонтитула, но она тоже стала плавной и неправильной

У RelativeLayout было больше проблем в 1.5, но мне все еще нравится:)

8 голосов
/ 28 ноября 2012

Чувак, это старое, но, похоже, наверху поисков, поэтому я собираюсь комментировать.

Я думаю, что хитрость в том, что тег <merge> в сочетании с тегом <include> по существу удаляет любые виды «родительских» групп представлений на этом уровне. Итак, кого именно вы просите "layout_below" кого-то еще? Ни один. Никто. На этом уровне нет обзора.

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

4 голосов
/ 07 ноября 2011

Для позиционирования для работы с RelativeLayout необходимо установить параметры layout_ * во включаемом файле, а не в основном файле макета. Таким образом

main_layout.xml

<RelativeLayout
  android:id="@+id/header"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content">
   ....
</RelativeLayout>

<RelativeLayout 
  android:id="@+id/footer"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:layout_alignParentBottom="true">
    .....
</RelativeLayout>

<include layout="@layout/content_layout" />

content_layout.xml

<merge xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
    android:id="@+id/content"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_above="@id/footer"
    android:layout_below="@id/header" >

    ....
</RelativeLayout>
</merge>

Это явно не то, что нам нужно разработчикам, но это единственное решение, которое я нашел, чтобы избежать дублирования xml

1 голос
/ 23 февраля 2010

атрибуты android: layout_ * кажутся игнорироваться при использовании в include тег и все объединенные макеты отображаются друг на друга.

Я предполагаю, что из правил компоновки нельзя ссылаться на android:id атрибуты, которые определены для <include> элементов, только те, которые находятся на "реальных" виджетах и ​​контейнерах.

Кроме того, если кто-то может придумать способ мне просто иметь один макет слияния XML файл вместо 5, который будет с благодарностью.

Просто: поместите их все в один файл.

Я не мог найти способ сделать это потому что мне нужно иметь доступ к каждому пункт в файлах макета слияния в выполнения

Если у вас есть один элемент <include> или 1000, все содержимое должно быть доступно во время выполнения. Единственное исключение - если у вас есть дублированные атрибуты android:id - вам нужно правильно распределить вызовы findViewById(), чтобы получить правильный, точно так же, как вы это делаете при получении виджетов из строки ListView.

Если вы можете создать пример проекта, который использует 2+ файлы слияния, где вы можете продемонстрировать, что содержимое не доступно во время выполнения, дайте мне знать.

0 голосов
/ 20 февраля 2018

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

TL: DR: просто удалите теги, переместите определения xmlns в реальную область просмотра макета, и все будет хорошо.

До:

<merge
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <...ui.component.BorderCardView
        android:layout_width="112dp"
        android:layout_height="32dp"
        app:cardCornerRadius="4dp"
        app:cardUseCompatPadding="true">

        <ImageView
            android:layout_width="16dp"
            android:layout_height="16dp"
            android:src="@drawable/ic_logout"
            android:tint="@color/divider" />

    </...ui.component.BorderCardView>
</merge>

Рабочая:

<...ui.component.BorderCardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="112dp"
    android:layout_height="32dp"
    app:cardCornerRadius="4dp"
    app:cardUseCompatPadding="true">

    <ImageView
        android:layout_width="16dp"
        android:layout_height="16dp"
        android:src="@drawable/ic_logout"
        android:tint="@color/divider" />

</...ui.component.BorderCardView>
0 голосов
/ 02 августа 2017

В моем случае макет, который я пытался включить, начинается с тега <merge. Когда я изменил его на макет, скажем, <RelativeLayout это сработало. Ниже приведена иллюстрация.

РАБОЧАЯ

<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    tools:showIn="@layout/activity_home">

НЕ РАБОТАЕТ

<merge xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    tools:showIn="@layout/activity_home">
...