Il tag "include" di Android XML Layout funziona davvero?


84

Non riesco a sovrascrivere gli attributi quando utilizzo <include> nei miei file di layout Android. Quando ho cercato bug, ho trovato il problema rifiutato 2863 :

"include tag non funzionante (l'override dei parametri di layout non funziona mai)"

Poiché Romain indica che questo funziona nelle suite di test e nei suoi esempi, devo fare qualcosa di sbagliato.

Il mio progetto è organizzato in questo modo:

res/layout
  buttons.xml

res/layout-land
  receipt.xml

res/layout-port
  receipt.xml

Il buttons.xml contiene qualcosa del genere:

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

E i file ricezioni.xml verticale e orizzontale hanno un aspetto simile a:

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

Cosa mi manca?


Questa domanda viene indicata dagli strumenti per sviluppatori Android quando si tenta di utilizzare include in un modo che non è supportato.
ThomasW

Risposte:


132

Ho appena trovato il problema. Innanzitutto, puoi solo sovrascrivere gli attributi layout_ *, quindi lo sfondo non funzionerà. Questo è un comportamento documentato e semplicemente una mia svista.

Il vero problema si trova in 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);
   }
}

Se il tag <include> non include sia layout_width che layout_height, la RuntimeException si verifica e viene gestita silenziosamente, senza alcuna istruzione di log.

La soluzione è includere sempre sia layout_width che layout_height quando si utilizza il tag <include>, se si desidera sovrascrivere uno qualsiasi degli attributi layout_ *.

Il mio esempio dovrebbe cambiare in:

<include
      android:id="@+id/buttons_override"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      layout="@layout/buttons"/>

33
Questo è ridicolo. Non sono mai stato in grado di farlo funzionare, e ho persino visto la documentazione menzionare la necessità sia dell'altezza che della larghezza se si cerca di sovrascrivere le dimensioni, che presumevo fossero altezza e larghezza. Tuttavia, tutto ciò che stavo cercando di ignorare è il margine, che non è davvero una dimensione. Perché diavolo devo specificare entrambi o anche uno qualsiasi di quelli quando tutto quello che voglio cambiare è layout_marginRight? Grrr, Android, a volte mi frustri troppo.
Artem Russakovskii

1
Cordiali saluti, Android Lint ti darà un errore (parametro layout layout_height ignorato a meno che layout_width non sia specificato anche nel tag <include>) se non stai sovrascrivendo gli attributi di altezza e larghezza
binario

10

Ho inviato una richiesta di miglioramento per consentire la sostituzione di tutti gli attributi inclusi:

Supponiamo di avere due layout identici diversi dai valori di un TextViewcampo. Al momento, ho modificato il layout in fase di esecuzione o duplicato l'XML.

Ad esempio, per passare due parametri con valori "hello" e "world" a layout1:

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

layout1a.xml:

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

Un'implementazione alternativa romperebbe l'incapsulamento e consentirebbe all'istruzione include di sovrascrivere valori come:

<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
Prendendo in considerazione il nuovo materiale di associazione dati, ora <include>viene utilizzato ancora più spesso, l'override di attr è una caratteristica davvero
indispensabile

1

Ho scoperto che a volte mi manca l'inclusione del tag android: id quando si utilizza il generatore di GUI in Eclipse. Assicurandomi (quando noto) di aggiungere in un TextView dal builder, l'id che sto usando nel layout ListView.

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

diventa

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

Invece di ottenere "false", "false" ottengo :) e include il funzionamento corretto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.