Attributs personnalisés dans styles.xml

178

J'ai créé un widget personnalisé et je le déclare dans layout.xml. J'ai également ajouté des attributs personnalisés dans attr.xml. Cependant, lorsque vous essayez de déclarer ces attributs dans un style dans styles.xml, cela me donneNo resource found that matches the given name: attr 'custom:attribute'.

J'ai mis le xmlns:custom="http://schemas.android.com/apk/res/com.my.package"dans toutes les balises dans styles.xml, y compris <?xml>, <resources>et <style>, mais cela me donne toujours la même erreur, qu'il ne peut pas trouver mon espace de noms XML personnalisé.

Cependant, je peux utiliser mon espace de noms pour attribuer manuellement des attributs à la vue dans mon layout.xml, donc il n'y a rien de mal avec l'espace de noms. Mon problème est de rendre styles.xml conscient de mon attr.xml.

styler1972
la source
1
cutsom:xmlns=...?? ne devrait pas être xmlns:cutsom=...?
Selvin
Ouais, c'est ce que j'obtiens pour ne pas utiliser le copier / coller, merci
styler1972

Réponses:

362

Je l'ai compris! La réponse est de NE PAS spécifier l'espace de noms dans le style.

<?xml version="1.0" encoding="utf-8" ?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <style name="CustomStyle">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>

        <item name="custom_attr">value</item> <!-- tee hee -->
    </style>
</resources>
styler1972
la source
13
L'erreur disparaît, mais mon point de vue n'adopte pas la valeur d'attribut, alors qu'elle adopte les autres attributs (non personnalisés). Mon attribut particulier est une énumération. L'extrait ci-dessus fonctionne-t-il pour vous?
Paul Lammertsma
@PaulLammertsma J'utilise une énumération et cela ne semble pas non plus fonctionner pour moi. Si vous ne disposez pas de l'attribut xmlns d'espace de nom personnalisé, vous pouvez en fait taper la valeur de votre choix pour l'attribut de nom d'élément et il se compilera.
David Snabel-Caunt
@DavidCaunt J'ai finalement obtenu ce sur quoi je travaillais . J'ai finalement utilisé une chaîne pour le declare-stylableau lieu d'une énumération. Je ne sais pas pourquoi les énumérations ne fonctionnaient pas, mais cette solution de contournement était assez bonne pour moi.
Paul Lammertsma
3
Cela ne compile même pas pour moi, en utilisant l'API lvl 16.
David Miler
3
Bien que cela fonctionne, je soupçonne qu'il y aurait un problème de résolution des attributs si un attribut avec le même nom existait dans deux ou plusieurs packages mais avec des noms de packages différents.
AndroidDev
43

la réponse ci-dessus fonctionne pour moi, j'ai essayé un petit changement, je déclare stylable pour une classe dans l'élément de ressources.

<declare-styleable name="VerticalView">
    <attr name="textSize" format="dimension" />
    <attr name="textColor" format="color" />
    <attr name="textBold" format="boolean" />
</declare-styleable>

dans declare-styleable , l' attribut name faisait référence à un nom de classe, donc j'ai eu un appel de classe de vue "com.my.package.name.VerticalView", il représentait que cette déclaration devait être utilisée dans VerticalView ou des sous-classes de VerticalView. afin que nous puissions déclarer le style comme ceci:

<resources>
    <style name="verticalViewStyle">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">36dip</item>

        <item name="textSize">28sp</item>  <!-- not namespace prefix -->
        <item name="textColor">#ff666666</item>
        <item name="textBold">true</item>
    </style>
</resources>

c'est pourquoi nous n'avons pas déclaré d'espace de noms à l'élément resources, cela fonctionne toujours.

VinceStyling
la source
11

values ​​/ styles.xml

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    ...
    <item name="defaultButtonColor">@color/red</item>
    <item name="defaultButtonHeight">@dimen/dp_100</item>
</style>

valeurs / attrs.xml

<resources>
    <attr name="defaultButtonColor" format="reference" />
    <attr name="defaultButtonHeight" format="reference"/>
</resources>

values ​​/ colors.xml

<resources>
    <color name="red">#f00</color>
</resources>

values ​​/ dimens.xml

<resources>
    <dimen name="dp_100">100dp</dimen>
</resources>

En utilisant

<Button
    android:layout_width="wrap_content"
    android:layout_height="?attr/defaultButtonHeight"
    android:text="Button"
    android:textColor="?attr/defaultButtonColor"
    />

entrez la description de l'image ici

DEMO

Phan Van Linh
la source
10

La modification de Styler et Vince a fonctionné pour moi. Je voulais souligner que l'explication de @ vince n'est peut-être pas tout à fait exacte.

Pour tester l'hypothèse que l'attribut name de la declare-styleablecorrespondance avec le nom de la classe de vue personnalisée nous permet d'accéder à l'attribut personnalisé sans espace de noms, j'ai changé le nom de la declare-styleable(la vue personnalisée a été nommée TestViewFont:

<declare-styleable name="TextViewFont2">
    <attr name="font" format="integer"/>
</declare-styleable>

J'ai ensuite changé l' obtainStyledAttributesappel dans la vue personnalisée pour refléter ceci:

TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TextViewFont2, 0, 0);

Le code fonctionnait toujours. Je ne pense donc pas que ce soit une sorte d'introspection de la part declare-styleablede la classe dont il porte le nom.

Ainsi, je suis amené à croire que tous les attributs personnalisés peuvent être utilisés pour déclarer un style sans faire référence à un espace de noms.

Quoi qu'il en soit, merci pour tous les types d'aide, cela a résolu mon problème.

Abid H. Mujtaba
la source
En fait, les attributs partagent le même espace de noms, qu'ils soient déclarés dans un declare-styleablebloc ou non. (désolé, je ne trouve pas la page de référence pour cela…) Sauf pour les attributs de l' androidespace de noms, vous ne devez indiquer que le nom de l'attribut.
pr-shadoko
3
  • Définissez quelques attributs

<declare-styleable name="refreshPullRefreshLayout">
        <attr name="refreshColors" format="reference"/>
        <attr name="refreshColor" format="reference"/>
</declare-styleable>
  • Utilisez-le dans un fichier de mise en page comme

<com.aolphn.PullRefreshLayout
     app:refreshColor="@color/main_green"
     app:refreshColors="@array/refresh_color"/>
  • Enfin, utilisez-le dans un fichier de style

    La différence entre le fichier de style et le fichier de mise en page est que nous n'ajoutons pas de prefiex app:
<style name="refreshStyle">
    <item name="refreshColor">@color/main_green</item>
    <item name="refreshColors">@array/refresh_color</item>
</style>

Essayez-le, passez une bonne journée, cela fonctionne pour moi.

aolphn
la source
2

Au cas où cela aiderait quelqu'un d'autre, mon erreur était que ma classe de vue personnalisée appelait AttributeSet.getAttributeValue, par exemple

String fontName = attrs.getAttributeValue("http://schemas.android.com/apk/res-auto", "customFont");

... ce qui empêchait la lecture de mon attribut personnalisé pour ma vue personnalisée.

Le correctif était à utiliser obtainStyledAttributesdans ma vue personnalisée:

 TypedArray styleAttrs = context.obtainStyledAttributes(attrs, R.styleable.MyTextViewStyleable);
 String fontName = styleAttrs.getString(R.styleable.MyTextViewStyleable_customFont);

Un indice que cela fonctionne correctement est que vous pouvez Ctrl / Apple + cliquer sur R.styleable.MyTextViewStyleable_customFontpour accéder directement à votre définition attrs.xml.

Il m'a fallu un certain temps pour repérer cette différence critique entre mon code et les autres exemples, car l'attribut personnalisé fonctionnait bien lorsqu'il était transmis directement via le XML de mise en page (au lieu de via un style).

Dan J
la source