La balise "include" d'Android XML Layout fonctionne-t-elle vraiment?

84

Je ne peux pas remplacer les attributs lors de l'utilisation de <include> dans mes fichiers de mise en page Android. Lorsque j'ai recherché des bogues, j'ai trouvé le problème 2863 refusé :

"inclure la balise est cassée (remplacer les paramètres de mise en page ne fonctionne jamais)"

Puisque Romain indique que cela fonctionne dans les suites de tests et ses exemples, je dois faire quelque chose de mal.

Mon projet est organisé comme ceci:

res/layout
  buttons.xml

res/layout-land
  receipt.xml

res/layout-port
  receipt.xml

Le boutons.xml contient quelque chose comme ceci:

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

Et les fichiers reçus.xml portrait et paysage ressemblent à ceci:

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

Qu'est-ce que je rate?

Eric Burke
la source
Cette question est mentionnée par les outils de développement Android lorsque vous essayez d'utiliser l'inclusion d'une manière qui n'est pas prise en charge.
ThomasW

Réponses:

132

Je viens de trouver le problème. Tout d'abord, vous ne pouvez remplacer que les attributs layout_ *, donc l'arrière-plan ne fonctionnera pas. C'est un comportement documenté et simplement un oubli de ma part.

Le vrai problème se trouve dans 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);
   }
}

Si la balise <include> n'inclut pas à la fois layout_width et layout_height, l'exception RuntimeException se produit et est gérée silencieusement, même sans aucune instruction de journal.

La solution consiste à toujours inclure à la fois layout_width et layout_height lors de l'utilisation de la balise <include>, si vous souhaitez remplacer l'un des attributs layout_ *.

Mon exemple devrait changer en:

<include
      android:id="@+id/buttons_override"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      layout="@layout/buttons"/>
Eric Burke
la source
33
C'est ridicule. Je n'ai jamais réussi à faire fonctionner cela, et j'ai même vu la documentation mentionner qu'il fallait à la fois hauteur et largeur pour essayer de remplacer les dimensions, que je supposais être la hauteur et la largeur. Cependant, tout ce que j'essayais de remplacer, c'est la marge, qui n'est pas vraiment une dimension. Pourquoi diable dois-je spécifier les deux ou même l'un d'entre eux alors que tout ce que je veux changer est le layout_marginRight? Grrr, Android, parfois tu me frustre trop.
Artem Russakovskii
1
FYI Android Lint vous donnera une erreur (paramètre de mise en page layout_height ignoré sauf si layout_width est également spécifié sur la balise <include>) si vous ne remplacez pas les attributs de hauteur et de largeur
binaire
10

J'ai soumis une demande d'amélioration pour autoriser le remplacement de tous les attributs inclus:

Supposons que j'ai deux dispositions identiques autres que les valeurs d'un TextViewchamp. Actuellement, j'ai soit modifié la mise en page au moment de l'exécution, soit dupliqué le XML.

Par exemple, pour passer deux paramètres avec les valeurs "hello" et "world" à layout1:

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

layout1a.xml:

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

Une autre implémentation interromprait l'encapsulation et permettrait à l'instruction include de remplacer des valeurs telles que:

<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
la source
1
Compte tenu des nouveaux éléments de liaison de données, le <include>est utilisé encore plus souvent maintenant, le remplacement d'attr est une fonctionnalité vraiment indispensable
Dmitry Gryazin
1

J'ai trouvé que je manquais parfois d'inclure la balise android: id lors de l'utilisation du générateur d'interface graphique dans Eclipse. S'assurer (quand je remarque) que j'ajoute dans un TextView à partir du constructeur, l'id que j'utilise dans la disposition ListView.

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

devient

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

Au lieu d'obtenir «faux» «faux», j'obtiens :) et inclut le fonctionnement correct.

TheSolarSheriff
la source