Il existe une précieuse documentation sur le declare-styleable
balise par laquelle nous pouvons déclarer des styles personnalisés pour les composants. J'ai trouvé cette liste de valeurs valides pour l'attribut format
de la balise attr
. Bien que ce soit une bonne chose, cela n'explique pas comment utiliser certaines de ces valeurs. En parcourant attr.xml (la Android pour les attributs standard)), j'ai découvert que vous pouvez faire des choses comme:
<!-- The most prominent text color. -->
<attr name="textColorPrimary" format="reference|color" />
L'attribut format
peut évidemment être défini sur une combinaison de valeurs. Vraisemblablement, l'attribut format
aide l'analyseur à interpréter une valeur de style réelle. Puis j'ai découvert ceci dans attr.xml:
<!-- Default text typeface. -->
<attr name="typeface">
<enum name="normal" value="0" />
<enum name="sans" value="1" />
<enum name="serif" value="2" />
<enum name="monospace" value="3" />
</attr>
<!-- Default text typeface style. -->
<attr name="textStyle">
<flag name="normal" value="0" />
<flag name="bold" value="1" />
<flag name="italic" value="2" />
</attr>
Les deux semblent déclarer un ensemble de valeurs autorisées pour le style indiqué.
J'ai donc deux questions:
enum
et un autre pouvant prendre un ensemble de valeurs flag
?declare-styleable
fonctionne (autre que le reverse engineering du Android)?Il y a cette question ici: Définition d'attributs personnalisés avec certains info, mais pas beaucoup.
Et ceci post . Il contient de bonnes informations sur les drapeaux et les enums:
Indicateurs d'attribut XML personnalisés
Les drapeaux sont des types d'attributs spéciaux dans la mesure où ils ne sont autorisés que dans un très petit sous-ensemble de valeurs, à savoir celles qui sont définies sous la balise d'attribut. Les indicateurs sont spécifiés par un attribut "name" et un attribut "value". Les noms doivent être uniques dans ce type d'attribut, mais les valeurs ne doivent pas l'être. C’est la raison pour laquelle, lors de l’évolution de la plate-forme Android, nous avons eu “fill_parent” et “match_parent” mappés tous deux sur le même comportement. Leurs valeurs étaient identiques.
L'attribut name correspond au nom utilisé à la place de la valeur dans le XML de présentation et ne nécessite pas de préfixe d'espace de nom. Par conséquent, pour le "tilingMode" ci-dessus, j'ai choisi "centre" comme valeur d'attribut. J'aurais pu tout aussi facilement choisir "étiré" ou "répéter", mais rien d'autre. Aucune substitution dans les valeurs réelles n'aurait été autorisée.
L'attribut value doit être un entier. Vous avez le choix entre une représentation numérique hexadécimale ou standard. Il y a quelques endroits dans le code Android) où les deux sont utilisés et le compilateur Android est heureux de l’accepter.
Enumères d'attributs XML personnalisés
Les énumérations sont utilisées presque de la même manière que les drapeaux avec une disposition, elles peuvent être utilisées indifféremment avec des entiers. Sous le capot, les énumérations et les entiers sont mappés sur le même type de données, à savoir un entier. Lorsqu'ils apparaissent dans la définition d'attribut avec des entiers, les énumérations servent à empêcher les "nombres magiques" qui sont toujours mauvais. C'est pourquoi vous pouvez avoir un "Android: layout_width" avec une dimension, un entier ou la chaîne nommée "fill_parent".
Pour mettre cela dans le contexte, supposons que je crée un attribut personnalisé appelé "layout_scroll_height" qui accepte soit un entier, soit une chaîne "scroll_to_top". Pour cela, j’ajouterais un attribut de format "entier" et le suivrais avec l’énumération:
<attr name="layout_scroll_height" format="integer"> <enum name="scroll_to_top" value="-1"/> </attr>
La seule stipulation lors de l’utilisation de Enums de cette manière est qu’un développeur utilisant votre vue personnalisée puisse délibérément placer la valeur "-1" dans les paramètres de présentation. Cela déclencherait la logique de cas particuliers de "scroll_to_top". Un tel comportement inattendu (ou attendu) pourrait rapidement reléguer votre bibliothèque dans la pile de "code hérité" si les valeurs Enum étaient mal choisies.
Selon moi, les vraies valeurs que vous pouvez ajouter en réalité à un attribut sont limitées par ce que vous pouvez en obtenir. Vérifiez la référence de la classe AttributeSet
ici pour plus de conseils.
Vous pouvez obtenir:
getAttributeBooleanValue
),getAttributeFloatValue
),getAttributeIntValue
),getAttributeUnsignedIntValue
),getAttributeValue
)La réponse de @Aleadam est très utile, mais elle omet une différence majeure entre enum
et flag
. Le premier est destiné à nous permettre de choisir une valeur et une seule valeur lorsque nous affectons l'attribut correspondant à une vue. Les valeurs de ce dernier peuvent toutefois être combinées à l'aide de l'opérateur binaire OR.
Un exemple, dans res/values/attr.xml
<!-- declare myenum attribute -->
<attr name="myenum">
<enum name="zero" value="0" />
<enum name="one" value="1" />
<enum name="two" value="2" />
<enum name="three" value="3" />
</attr>
<!-- declare myflags attribute -->
<attr name="myflags">
<flag name="one" value="1" />
<flag name="two" value="2" />
<flag name="four" value="4" />
<flag name="eight" value="8" />
</attr>
<!-- declare our custom widget to be styleable by these attributes -->
<declare-styleable name="com.example.MyWidget">
<attr name="myenum" />
<attr name="myflags" />
</declare-styleable>
Dans res/layout/mylayout.xml
nous pouvons maintenant faire
<com.example.MyWidget
myenum="two"
myflags="one|two"
... />
Ainsi, une énumération sélectionne l'une de ses valeurs possibles, tandis que les indicateurs peuvent être combinés. Les valeurs numériques doivent refléter cette différence. En général, vous voudrez que la séquence aille 0,1,2,3,...
pour les énumérations (à utiliser comme index de tableau, par exemple) et les indicateurs à parcourir 1,2,4,8,...
afin qu’ils puissent être ajoutés ou supprimés indépendamment, en utilisant bitwise OR |
pour combiner des drapeaux.
Nous pourrions définir explicitement les "méta flags" avec des valeurs qui ne sont pas une puissance de 2 et introduire ainsi une sorte de raccourci pour les combinaisons courantes. Par exemple, si nous avions inclus cela dans notre myflags
déclaration
<flag name="three" value="3" />
alors nous aurions pu écrire myflags="three"
au lieu de myflags="one|two"
, pour des résultats complètement identiques à 3 == 1|2
.
Personnellement, j'aime toujours inclure
<flag name="none" value="0" /> <!-- or "normal, "regular", and so on -->
<flag name="all" value="15" /> <!-- 15 == 1|2|4|8 -->
ce qui me permettra de désactiver ou de mettre tous les drapeaux à la fois.
Plus subtilement, il se peut qu'un drapeau soit impliqué par un autre. Donc, dans notre exemple, supposons que le drapeau eight
en cours de définition force le drapeau four
(s'il ne l'était pas déjà). Nous pourrions alors redéfinir eight
pour pré-inclure, pour ainsi dire, le drapeau four
,
<flag name="eight" value="12" /> <!-- 12 == 8|4 -->
Enfin, si vous déclarez les attributs dans un projet de bibliothèque mais souhaitez les appliquer aux présentations d'un autre projet (dépendant de la bibliothèque), vous devez utiliser un préfixe d'espace de nom que vous devez lier dans l'élément racine XML. Par exemple.,
<RelativeLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:auto="http://schemas.Android.com/apk/res-auto"
... >
<com.example.MyWidget
auto:myenum="two"
auto:myflags="one|two"
... />
</RelativeLayout>