Czy tag XML układu systemu Android „zawiera” naprawdę działa?

84

Nie mogę przesłonić atrybutów, używając <include> w moich plikach układu Androida. Kiedy szukałem błędów, znalazłem odrzucony numer 2863 :

„tag include jest uszkodzony (nadpisywanie parametrów układu nigdy nie działa)”

Ponieważ Romain wskazuje, że to działa w zestawach testowych i jego przykładach, muszę robić coś źle.

Mój projekt jest zorganizowany w następujący sposób:

res/layout
  buttons.xml

res/layout-land
  receipt.xml

res/layout-port
  receipt.xml

Plik buttons.xml zawiera coś takiego:

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

Pliki recepty w orientacji pionowej i poziomej wyglądają następująco:

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

czego mi brakuje?

Eric Burke
źródło
Narzędzia deweloperskie systemu Android odnoszą się do tego pytania, gdy próbujesz użyć dołączania w sposób, który nie jest obsługiwany.
ThomasW

Odpowiedzi:

132

Właśnie znalazłem problem. Po pierwsze, możesz przesłonić tylko atrybuty layout_ *, więc tło nie będzie działać. To jest udokumentowane zachowanie i po prostu przeoczenie z mojej strony.

Prawdziwy problem można znaleźć w 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);
   }
}

Jeśli tag <include> nie zawiera zarówno layout_width, jak i layout_height, wyjątek RuntimeException występuje i jest dyskretnie obsługiwany, nawet bez żadnej instrukcji dziennika.

Rozwiązaniem jest zawsze uwzględnianie zarówno layout_width, jak i layout_height, gdy używasz tagu <include>, jeśli chcesz przesłonić którykolwiek z atrybutów layout_ *.

Mój przykład powinien zmienić się na:

<include
      android:id="@+id/buttons_override"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      layout="@layout/buttons"/>
Eric Burke
źródło
33
To jest niedorzeczne. Nigdy nie udało mi się to uruchomić, a nawet widziałem w dokumentacji, że potrzebuję zarówno wysokości, jak i szerokości, jeśli próbowałem zastąpić wymiary, które, jak zakładałem, były wysokością i szerokością. Jednak wszystko, co próbowałem zastąpić, to margines, który tak naprawdę nie jest wymiarem. Dlaczego do cholery muszę określać oba te lub nawet którekolwiek z nich, skoro wszystko, co chcę zmienić, to layout_marginRight? Grrr, Android, czasami za bardzo mnie frustrujesz.
Artem Russakovskii
1
FYI Android Lint wyświetli błąd (parametr układu layout_height jest ignorowany, chyba że w tagu <include> określono również layout_width), jeśli nie nadpisujesz zarówno atrybutów wysokości, jak i szerokości
binarny
10

Przesłałem prośbę o ulepszenie, aby umożliwić zastąpienie wszystkich dołączonych atrybutów:

Załóżmy, że mam dwa identyczne układy inne niż wartości TextViewpola. Obecnie albo zmodyfikowałem układ w czasie wykonywania, albo zduplikowałem XML.

Na przykład aby przekazać dwa parametry z wartościami „hello” i „world” do układu1:

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

layout1a.xml:

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

Alternatywna implementacja przerwałaby hermetyzację i umożliwiłaby instrukcji include zastąpienie wartości takich jak:

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

Jeff Axelrod
źródło
1
Biorąc pod uwagę nowe elementy związane z wiązaniem danych, <include>jest ono obecnie używane nawet częściej, nadpisywanie
atr
1

Zauważyłem, że czasami brakuje mi dodawania tagu android: id podczas korzystania z kreatora GUI w Eclipse. Upewniając się (kiedy zauważę), że dodaję do TextView z konstruktora identyfikator, którego używam w układzie ListView.

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

staje się

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

Zamiast otrzymywać „false” „false” otrzymuję :) i obejmuje działanie OK.

TheSolarSheriff
źródło