Действительно ли работает тег «include» в Android XML Layout?

84

Я не могу переопределить атрибуты при использовании <include> в моих файлах макета Android. Когда я искал ошибки, я обнаружил отклоненную проблему 2863 :

"включаемый тег не работает (переопределение параметров макета никогда не работает)"

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

Мой проект организован так:

res/layout
  buttons.xml

res/layout-land
  receipt.xml

res/layout-port
  receipt.xml

В файле buttons.xml содержится что-то вроде этого:

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

  <Button .../>

  <Button .../>
</LinearLayout>

А файлы квитанции с книжной и альбомной ориентацией выглядят примерно так:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

  ...

  <!-- Overridden attributes never work. Nor do attributes like
       the red background, which is specified here. -->
  <include
      android:id="@+id/buttons_override"
      android:background="#ff0000"
      android:layout_width="fill_parent"
      layout="@layout/buttons"/>

</LinearLayout>

Что мне не хватает?

Эрик Берк
источник
На этот вопрос ссылаются инструменты разработчика Android, когда вы пытаетесь использовать include способом, который не поддерживается.
ThomasW

Ответы:

132

Я только что нашел проблему. Во-первых, вы можете переопределить только атрибуты layout_ *, поэтому фон не будет работать. Это задокументированное поведение и просто недосмотр с моей стороны.

Настоящая проблема находится в LayoutInflater.java:

// We try to load the layout params set in the <include /> tag. If
// they don't exist, we will rely on the layout params set in the
// included XML file.
// During a layoutparams generation, a runtime exception is thrown
// if either layout_width or layout_height is missing. We catch
// this exception and set localParams accordingly: true means we
// successfully loaded layout params from the <include /> tag,
// false means we need to rely on the included layout params.
ViewGroup.LayoutParams params = null;
try {
   params = group.generateLayoutParams(attrs);
} catch (RuntimeException e) {
   params = group.generateLayoutParams(childAttrs);
} finally {
   if (params != null) {
     view.setLayoutParams(params);
   }
}

Если тег <include> не включает как layout_width, так и layout_height, возникает исключение RuntimeException, которое обрабатывается автоматически, даже без каких-либо операторов журнала.

Решение состоит в том, чтобы всегда включать и layout_width, и layout_height при использовании тега <include>, если вы хотите переопределить любой из атрибутов layout_ *.

Мой пример должен измениться на:

<include
      android:id="@+id/buttons_override"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      layout="@layout/buttons"/>
Эрик Берк
источник
33
Это нелепо. Мне никогда не удавалось заставить это работать, и я даже видел в документации упоминание о необходимости как высоты, так и ширины при попытке переопределить размеры, которые, как я предполагал, были высотой и шириной. Однако все, что я пытался переопределить, - это маржа, которая на самом деле не является измерением. Какого черта мне нужно указывать оба или даже любой из них, когда все, что я хочу изменить, - это layout_marginRight? Grrr, Андроид, иногда ты меня слишком расстраиваешь.
Артем Русаковский
1
FYI Android Lint выдаст вам ошибку (параметр макета layout_height игнорируется, если layout_width также не указана в теге <include>), если вы не переопределяете атрибуты высоты и ширины
двоичный код
10

Я отправил запрос на улучшение, чтобы разрешить переопределение всех включенных атрибутов:

Предположим, у меня есть два идентичных макета, отличных от значений TextViewполя. В настоящее время я либо изменяю макет во время выполнения, либо дублирую XML.

Например, чтобы передать в layout1 два параметра со значениями «hello» и «world»:

<include layout="@layout/layout1a" params="textView=hello|editText=world" />

layout1a.xml:

<merge><TextView text="@param/textView"><EditText hint="@param/editText"></merge>

Альтернативная реализация нарушит инкапсуляцию и позволит оператору include переопределять такие значения, как:

<include layout="@layout/layout1b" overrides="@id/textView.text=hello|@id/editText.hint=world" />

layout1b.xml:

<merge><TextView id="@+id/textView"><EditText hint="@+id/editText"></merge>

Джефф Аксельрод
источник
1
Принимая во внимание новый механизм привязки данных, <include>теперь используется все чаще, переопределение attr - действительно необходимая функция
Дмитрий Грязин
1

Я обнаружил, что иногда пропускаю включение тега android: id при использовании конструктора графического интерфейса в Eclipse. Убедившись (когда я замечаю), что я добавляю в TextView из построителя идентификатор, который я использую в макете ListView.

<TextView android:text="@+id/textView1"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" />
...

становится

<TextView android:id="@+id/textView1"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" />
...

Вместо того, чтобы получать "ложь" "ложь", я получаю :) и включает работает нормально.

TheSolarSheriff
источник