Atributos personalizados en styles.xml

178

He creado un widget personalizado y lo estoy declarando en layout.xml. También he agregado algunos atributos personalizados en attr.xml. Sin embargo, cuando intento declarar estos atributos en un estilo en styles.xml, me daNo resource found that matches the given name: attr 'custom:attribute'.

He incluido xmlns:custom="http://schemas.android.com/apk/res/com.my.package"todas las etiquetas en styles.xml, incluidos <?xml>, <resources>y <style>, pero aún me da el mismo error, que no puede encontrar mi espacio de nombres XML personalizado.

Sin embargo, puedo usar mi espacio de nombres para asignar manualmente atributos a la vista en mi layout.xml, por lo que no hay nada de malo en el espacio de nombres. Mi problema radica en que styles.xml conozca mi attr.xml.

styler1972
fuente
1
cutsom:xmlns=...?? no debería ser xmlns:cutsom=...?
Selvin
Sí, eso es lo que obtengo por no usar copiar / pegar, gracias
styler1972

Respuestas:

362

¡Me lo imaginé! La respuesta es NO especificar el espacio de nombres en el estilo.

<?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
fuente
13
El error desaparece, pero mi vista no adopta el valor del atributo, mientras que sí adopta los otros atributos (no personalizados). Mi atributo particular es una enumeración. ¿El fragmento anterior funciona para ti?
Paul Lammertsma
@PaulLammertsma Estoy usando una enumeración y esto tampoco parece funcionar para mí. Si no tiene el atributo personalizado xmlns de espacio de nombres, puede escribir cualquier valor que desee para el atributo de nombre del elemento y se compilará.
David Snabel-Caunt
@DavidCaunt Eventualmente conseguí lo que estaba trabajando en funcionamiento. Finalmente utilicé una cadena para el en declare-stylablelugar de una enumeración. No estoy seguro de por qué las enumeraciones no funcionaban, pero esta solución fue lo suficientemente buena para mí.
Paul Lammertsma
3
Esto ni siquiera se compila para mí, usando API lvl 16.
David Miler
3
Si bien esto funciona, sospecho que habría un problema para resolver los atributos si existiera un atributo con el mismo nombre en dos o más paquetes pero con nombres de paquete diferentes.
AndroidDev
43

la respuesta anterior me funcionó, probé un pequeño cambio, declaro estilizable para una clase en el elemento de recursos.

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

en declare-styleable , el atributo de nombre hacía referencia a un nombre de clase, por lo que tuve una clase de vista llamada "com.my.package.name.VerticalView", representaba que esta declaración debe usarse en VerticalView o subclases de VerticalView. para que podamos declarar un estilo como este:

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

Es por eso que no declaramos el espacio de nombres en el elemento de recursos, todavía funciona.

VinceStyling
fuente
11

valores / styles.xml

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

valores / attrs.xml

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

valores / colores.xml

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

valores / dimens.xml

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

Utilizando

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

ingrese la descripción de la imagen aquí

MANIFESTACIÓN

Phan Van Linh
fuente
10

La modificación de Styler y Vince funcionó para mí. Quería señalar que la explicación de @vince puede no ser del todo precisa.

Para probar la hipótesis de que el atributo de nombre de la declare-styleablecoincidencia con el nombre de la clase de vista personalizada nos permite acceder al atributo personalizado sin un espacio de nombres, cambié el nombre de declare-styleable(la vista personalizada se llamó TestViewFont:

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

Luego cambié la obtainStyledAttributesllamada en la vista personalizada para reflejar esto:

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

El código seguía funcionando. Así que no creo que sea algún tipo de introspección por parte declare-styleablede la clase que lleva su nombre.

Por lo tanto, me hacen creer que cualquier atributo personalizado se puede usar para declarar un estilo sin hacer referencia a un espacio de nombres.

De todos modos, gracias por toda la ayuda chicos, resolvió mi problema.

Abid H. Mujtaba
fuente
En realidad, los atributos comparten el mismo espacio de nombres, ya sea que se declaren en un declare-styleablebloque o no. (lo siento, no puedo encontrar la página de referencia para esto ...) Excepto por los atributos del androidespacio de nombres, solo debe indicar el nombre del atributo.
pr-shadoko
3
  • Definir algunos atributos.

<declare-styleable name="refreshPullRefreshLayout">
        <attr name="refreshColors" format="reference"/>
        <attr name="refreshColor" format="reference"/>
</declare-styleable>
  • Úselo en el archivo de diseño como

<com.aolphn.PullRefreshLayout
     app:refreshColor="@color/main_green"
     app:refreshColors="@array/refresh_color"/>
  • Finalmente úsalo en el archivo de estilo

    La diferencia entre el archivo de estilo y el archivo de diseño es que no agregamos prefiex app:
<style name="refreshStyle">
    <item name="refreshColor">@color/main_green</item>
    <item name="refreshColors">@array/refresh_color</item>
</style>

Pruébalo, que tengas un buen día, esto funciona para mí.

aolphn
fuente
2

En caso de que ayude a alguien más, mi error fue que mi clase de vista personalizada estaba llamando a AttributeSet.getAttributeValue, por ejemplo

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

... lo que resultó en que mi atributo personalizado no se leyera en mi vista personalizada.

La solución fue usar obtainStyledAttributesen mi vista personalizada:

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

Una pista de que esto funciona correctamente es que puede hacer Ctrl / Apple + hacer clic en el botón R.styleable.MyTextViewStyleable_customFontpara ir directamente a su definición de attrs.xml.

Me tomó un tiempo detectar esta diferencia crítica entre mi código y los otros ejemplos, ya que el atributo personalizado funcionó bien cuando se pasó directamente a través del diseño XML (en lugar de a través de un estilo).

Dan J
fuente