Как заставить RelativeLayout работать со слиянием и включением?
Уже несколько дней я пытаюсь сделать свои макеты более эффективными, конвертируя из нескольких вложенных уровней. 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 ответов
Существует проблема с тегом включения. Проверьте: https://issuetracker.google.com/issues/36908001
Чтобы исправить это, убедитесь, что вы перезаписали ОБА layout_width
а также layout_height
при включении, иначе все будет игнорироваться.
Смотрите ответ с более высоким рейтингом ниже. Моя сильно устарела
я могу решить одну проблему, поднятую Джастином: неспособность RelativeLayout управлять позицией включения (по крайней мере, в этом простом случае на эмуляторе 1.6)
CommonsWare предлагает обернуть включения в уникальный родительский контейнер, но делает это для того, чтобы помочь адресовать и определять области видимости с одинаковыми именами в пределах включений Джастина.
Каждый из них должен иметь уникальный родительский контейнер, и вы должны вызывать findViewById() для этого контейнера (ViewGroup), а не для Activity.
Фактически, вы также должны сделать это для того, чтобы 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>
Включение нижнего колонтитула не будет выравниваться по низу родительского элемента без окружающего LinearLayout. Я бы не назвал это ожидаемым поведением.
Кроме того, кажется, что WebView хорошо прикрепляется к заголовку по идентификатору, но я считаю, что это иллюзия, поскольку он просто течет ниже заголовка по вертикали. Я также попытался установить кнопку прямо над включением нижнего колонтитула, но она тоже стала плавной и неправильной
У RelativeLayout было больше проблем в 1.5, но мне все еще нравится:)
Чувак, это старое, но, похоже, наверху поисков, поэтому я собираюсь прокомментировать.
Я думаю, что хитрость в том, что <merge>
тег в сочетании с <include>
тег по существу удаляет любой вид "родительской" группы представления на этом уровне. Итак, кого именно вы просите "layout_below" кого-то еще? Ни один. Никто. На этом уровне нет представления.
<merge>
тег принимает дочерние представления и вставляет их прямо в родительский элемент <include>
тег. Поэтому вы должны попросить детей в макете, который вы включаете, соответствующим образом закрепить себя.
Чтобы позиционирование работало с 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
Пытаться :
<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
tools:showIn="@layout/activity_home">
При использовании в теге include атрибуты android:layout_* игнорируются, и все объединенные макеты отображаются друг над другом.
Я думаю, что вы не можете ссылаться, из правил макета, android:id
атрибуты, которые определены на <include>
элементы, только те, которые находятся на "настоящих" виджетах и контейнерах.
Кроме того, если кто-нибудь может придумать, как мне иметь один файл макета слияния xml вместо 5, это было бы очень полезно.
Просто: поместите их все в один файл.
Я не мог найти способ сделать это, потому что мне нужно иметь доступ к каждому элементу в файлах макета слияния во время выполнения
Есть ли у вас один <include>
элемент или 1000, все содержимое должно быть доступно во время выполнения. Единственное исключение, если вы дублировали android:id
атрибуты - вам нужно правильно сфокусировать findViewById()
звонки, чтобы получить правильный, точно так же, как вы делаете это при получении виджетов из строки ListView.
Если вы можете создать пример проекта, который использует файлы слияния 2+, где вы можете продемонстрировать, что содержимое недоступно во время выполнения, дайте мне знать.
У меня была такая же проблема и даже определение 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>
В моем случае макет, который я пытался включить, начинается с <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">