Attributs du même nom dans attrs.xml pour une vue personnalisée

180

J'écris quelques vues personnalisées qui partagent des attributs du même nom. Dans leur <declare-styleable>section respective de attrs.xmlj'aimerais utiliser les mêmes noms pour les attributs:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyView1">
        <attr name="myattr1" format="string" />
        <attr name="myattr2" format="dimension" />
        ...
    </declare-styleable>

    <declare-styleable name="MyView2">
        <attr name="myattr1" format="string" />
        <attr name="myattr2" format="dimension" />
        ...
    </declare-styleable>
</resources>

J'obtiens une erreur disant cela myattr1et myattr2sont déjà définis. J'ai trouvé que je devais omettre l' formatattribut for myattr1and myattr2in MyView2, mais si je fais cela, j'obtiens l'erreur suivante dans la console:

[2010-12-13 23:53:11 - MyProject] ERROR: In <declare-styleable> MyView2, unable to find attribute 

Y a-t-il un moyen d'accomplir cela, peut-être une sorte d'espacement de noms (juste deviner)?

Venator85
la source

Réponses:

401

Solution: extrayez simplement les attributs communs des deux vues et ajoutez-les directement en tant qu'enfants du <resources>nœud:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="myattr1" format="string" />
    <attr name="myattr2" format="dimension" />

    <declare-styleable name="MyView1">
        <attr name="myattr1" />
        <attr name="myattr2" />
        ...
    </declare-styleable>

    <declare-styleable name="MyView2">
        <attr name="myattr1" />
        <attr name="myattr2" />
        ...
    </declare-styleable>
</resources>
Venator85
la source
11
que se passe-t-il quand la myattr1chaîne est-elle entrée MyView1et l'entier compris MyView2?
foxx1337
4
Je ne pense pas, par exemple, nous pouvons avoir l'attribut «orientation» et pour certaines vues, il est «horizontal» / «vertical» et pour d'autres «paysage» / «portrait» / «carré». De mon point de vue, c'est un bogue (ou du moins un comportement incohérent) dans Android (gardez à l'esprit que: 1. les attributs stylables commencent toujours par prefix = nom de la vue et 2. si vous créez des projets de bibliothèque séparés pour de telles vues, tout fonctionnera bien )
se.solovyev
4
Lorsque je suis cette réponse, j'obtiens ERROR: In <declare-styleable> com_app_view_widget, unable to find attribute customAttr Pour toute la vue que j'essaie de déclarer. Des idées?
Dapp le
45
@Google: Design Crappy
Glenn Bech
6
@ foxx1337 Utilisez simplement <attr name="myattr1" format="string|integer" />. Travaille pour moi.
Mygod
58

Je publie cette réponse car la solution publiée ci-dessus n'a pas fonctionné pour moi dans Android Studio. J'ai besoin de partager mes attributs personnalisés parmi mes vues personnalisées, j'ai donc essayé la solution ci-dessus dans Android Studio mais je n'ai pas eu de chance. Alors j'expérimente et je cherche un moyen de le faire. J'espère que cela pourrait aider quelqu'un à la recherche du même problème.

  <?xml version="1.0" encoding="utf-8"?>
    <resources>
    <!-- parent styleable -->
     <declare-styleable name="MyView">
         <attr name="myattr1" format="string" />
         <attr name="myattr2" format="dimension" />
     </declare-styleable>

     <!-- inheriting parent styleable -->
     <!-- also note "myBackgroundColor" belongs to child styleable"MyView1"-->
    <declare-styleable name="MyView1" parent="MyView">
        <attr name="myattr1" />
        <attr name="myattr2" />
        <attr name="myBackgroundColor" format="color"/>
    </declare-styleable>


    <!-- inheriting parent styleable -->
    <!-- same way here "myfonnt" belongs to child styelable "MyView2" -->
    <declare-styleable name="MyView2" parent="MyView">
        <attr name="myattr1" />
        <attr name="myattr2" />
        <attr name="myfont" format="string"/>
        ...
    </declare-styleable>
</resources>

Cela fonctionne complètement pour moi. Nous devons rendre un parent stylable, puis hériter de ce parent stylable. Par exemple, comme je l'ai fait ci-dessus: Nom de style parent MyView et hérité de cela à mon autre stylable comme MyView1 et MyView2 respectivement.

Priya Singhal
la source
1
Cela a fonctionné pour moi. Je n'ai pas trouvé de moyen de référencer les attributs extraits dans le code à partir de la réponse acceptée.
Nemanja Kovacevic
Hmm ... c'est bizarre ... la solution acceptée semble bien fonctionner pour moi (targetSdkVersion 27). Peut-être parce que des attributs comme "text" sont courants et peuvent avoir existé dans d'autres attrs.xml ..?
Aba
J'ai essayé avec un nom qui est probablement rare et la solution acceptée fonctionnait toujours pour moi.
Aba
Je suis d'accord avec le premier commentaire! Il n'y a aucun moyen de référencer un attr extrait de typedArray. Par conséquent, vous devez définir un parent
stylable
pour que cela fonctionne , ne pas oublier de traiter cet attribut dans parent et non chez l' enfant (pour la classe MyView2droite: R.styleable.MyView2_myattr1, mal: R.styleable.MyView_myattr1)
vigilancer
28

Comme Priya Singhal a répondu, Android Studio nécessite que les noms d'attributs communs soient définis dans leur propre nom de style. Ils ne peuvent plus être à la racine.

Cependant, il y a quelques autres choses à noter (c'est pourquoi j'ajoute également une réponse):

  • Les styles courants n'ont pas besoin d'être nommés de la même manière qu'une vue. (Merci à cette réponse pour l'avoir signalé.)
  • Vous n'avez pas besoin d'utiliser l'héritage avec un parent.

Exemple

Voici ce que j'ai fait dans un projet récent qui a deux vues personnalisées qui partagent les mêmes attributs. Tant que les vues personnalisées ont toujours les noms des attributs et n'incluent pas de format, je peux toujours y accéder normalement à partir du code.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!-- common attributes to all custom text based views -->

    <declare-styleable name="TextAttributes">
        <attr name="text" format="string"/>
        <attr name="textSize" format="dimension"/>
        <attr name="textColor" format="color"/>
        <attr name="gravity">
            <flag name="top" value="48" />
            <flag name="center" value="17" />
            <flag name="bottom" value="80" />
        </attr>
    </declare-styleable>

    <!-- custom text views -->

    <declare-styleable name="View1">
        <attr name="text"/>
        <attr name="textSize"/>
        <attr name="textColor"/>
        <attr name="gravity"/>
    </declare-styleable>

    <declare-styleable name="View2">
        <attr name="text"/>
        <attr name="textSize"/>
        <attr name="textColor"/>
        <attr name="gravity"/>
    </declare-styleable>

</resources>

Exemple simplifié

En fait, je n'ai même pas besoin de mettre les attributs sous un nom personnalisé. Tant que je les définit (donnez-leur un format) pour au moins une vue personnalisée, je peux les utiliser n'importe où (sans le format). Donc, cela fonctionne également (et semble plus propre):

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="View1">
        <attr name="text" format="string"/>
        <attr name="textSize" format="dimension"/>
        <attr name="textColor" format="color"/>
        <attr name="gravity">
            <flag name="top" value="48" />
            <flag name="center" value="17" />
            <flag name="bottom" value="80" />
        </attr>
    </declare-styleable>

    <declare-styleable name="View2">
        <attr name="text"/>
        <attr name="textSize"/>
        <attr name="textColor"/>
        <attr name="gravity"/>
    </declare-styleable>

</resources>

Pour un grand projet, cependant, cela pourrait devenir compliqué et les définir en haut à un seul endroit pourrait être mieux (comme recommandé ici ).

Suragch
la source
Quel est le problème avec l'héritage? J'ai des hiérarchies de vues personnalisées dont les styles associés ne reflètent pas cette relation, qui ne peut être déduite dans les définitions de style associées que par les conventions de dénomination et les éléments spécifiques qui y sont définis (en notant que quelques-uns appartiennent à un stylable et quelques-uns à un autre). Je préfère le rendre explicite avec l' parentattribut, mais je n'ai pas vu beaucoup de messages suggérant son utilisation.
samis
@samis, je n'ai pas travaillé dessus depuis un moment, mais je ne sais rien de mal à l'utilisation parent. Je pense que je disais simplement que ce n'était pas nécessaire.
Suragch
Ce n'est pas obligatoire, j'ai juste créé une autre sous-classe autour d'un attribut supplémentaire que je ne voulais pas mettre dans la classe de base. J'utilise juste des commentaires et des conventions de dénomination pour indiquer la séparation.
samis
8

Merci Lewis, j'ai eu le même problème, et votre solution d'héritage m'a donné un indice pour le faire comme ci-dessous et cela fonctionne bien.Je viens de déclarer les attributs communs ci-dessus et de les réécrire dans le corps de la déclaration de style sans formatage. J'espère que ça aide quelqu'un

<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- common attributes -->
     <attr name="myattr1" format="string" />
     <attr name="myattr2" format="dimension" />

 <!-- also note "myBackgroundColor" belongs to child styleable"MyView1"-->
<declare-styleable name="MyView1" >
    <attr name="myattr1" />
    <attr name="myattr2" />
    <attr name="myBackgroundColor" format="color"/>
</declare-styleable>

<!-- same way here "myfonnt" belongs to child styelable "MyView2" -->
<declare-styleable name="MyView2" parent="MyView">
    <attr name="myattr1" />
    <attr name="myattr2" />
    <attr name="myfont" format="string"/>
    ...
</declare-styleable>

Hanieh Variani
la source
1

Juste au cas où quelqu'un serait toujours coincé avec ce problème après avoir essayé la solution disponible. Je suis resté avec ajouter un subtitleattribut avec le stringformat.

Ma solution est de supprimer le format.

avant:

<attr name="subtitle" format="string"/>

après:

<attr name="subtitle"/>

Ahmad Muzakki
la source