72

I'm trying to create custom attributes to my button but I dont know which format I must use to images in attributes declaration...

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

    <declare-styleable name="TCButton">
        <attr name="Text" format="string"/>
        <attr name="BackgroundImage" format="android:drawable"  />
    </declare-styleable>


</resources>

Error is in the format="android:drawable"...

Tiago Costa
  • 4,151
  • 12
  • 36
  • 54

3 Answers3

165

You can use format="integer", the resource id of the drawable, and AttributeSet.getDrawable(...).

Here is an example.

Declare the attribute as integer in res/values/attrs.xml:

<resources>
    <declare-styleable name="MyLayout">
        <attr name="icon" format="integer" />
    </declare-styleable>
</resources>

Set the attribute to a drawable id in your layout:

<se.jog.MyLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" 
    myapp:icon="@drawable/myImage"
/>

Get the drawable from the attribute in your custom widget component class:

ImageView myIcon;
//...
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyLayout);
Drawable drawable = a.getDrawable(R.styleable.MyLayout_icon);
if (drawable != null)
    myIcon.setBackgroundDrawable(drawable);

To see all options possible check the android src here

philipp
  • 4,133
  • 1
  • 36
  • 35
JOG
  • 5,590
  • 7
  • 34
  • 54
  • looking at this again, it could be added that a faulty namespace declaration will not give compile time errors. In this example, it could look like `xmlns:myapp="http://schemas.android.com/apk/res/se.jog.mob"` if `class MyLayout` is declared in `se.jog.mob`. – JOG Oct 31 '11 at 17:29
  • 12
    You should call `a.recycle()` when you are done using the styled attributes. – karl Jun 28 '13 at 17:39
  • 1
    In gradle projects, custom schema should always be "http://schemas.android.com/apk/res-auto" – Alon Burg Jul 28 '14 at 12:02
  • The method setBackgroundDrawable(Drawable) from the type View is deprecated – Scott Zhu Oct 30 '14 at 08:21
  • 1
    Yes, there is a question about the deprecation here: http://stackoverflow.com/questions/11947603/setbackground-vs-setbackgrounddrawable-android – JOG Oct 30 '14 at 09:00
  • 7
    Using integer didn't let me select from @drawable in the XML. I had tu use fromat="reference" and then it worked. – Distwo Apr 13 '15 at 21:10
  • Not working on Android 6 – Kishan Solanki Dec 10 '21 at 08:51
50

I think it will be better to use it as a simple reference:

<declare-styleable name="TCButton">
        <attr name="customText" format="string"/>
        <attr name="backgroundImage" format="reference"  />
</declare-styleable>

And set it in your xml like this:

<your.package.name.TCButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" 
    custom:customText="Some custom text"
    custom:backgroundImage="@drawable/myImage"
/>

And in your class set the attributes like this:

public TCButton(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MembershipItemView, 0, 0);

    String customText;
    Drawable backgroundImage;
    try {
        customText = a.getString(R.styleable.TCButton_customText);
        backgroundImage = a.getDrawable(R.styleable.TCButton_backgroundImage);
    } finally {
        a.recycle();
    }

    if(!TextUtils.isEmpty(customText)) {
      ((TextView)findViewById(R.id.yourTextView)).setText(customText);
    }

    if(null != backgroundImage) {                    
        ((ImageView)findViewById(R.id.yourImageView)).setBackgroundDrawable(backgroundImage);
    }
}

PS: Don't forget to add this line for the root element of the layout you are using your custom view in

xmlns:custom="http://schemas.android.com/apk/res-auto"

If you don't set this, you won't be able to access your custom attributes.

Ionut Negru
  • 6,186
  • 4
  • 48
  • 78
  • 1
    Custom backgroundImage attribute setting in your example is wrong. More like: custom:backgroundImage="@drawable/myImage" – gdakram Sep 22 '14 at 21:36
  • This is the best answer. When you use format="reference", you will see the dropdown list to choise resource at custom:backgroundImage="@drawable/myImage" – Nguyen Minh Hien Jul 05 '19 at 20:26
21

From AOSP code, I found how google engineers declare ImageView#src attr.

<declare-styleable name="ImageView">
    <attr name="src" format="reference|color" />
    <attr name="scaleType">
        <enum name="matrix" value="0" />
        <enum name="fitXY" value="1" />
        <enum name="fitStart" value="2" />
        <enum name="fitCenter" value="3" />
        <enum name="fitEnd" value="4" />
        <enum name="center" value="5" />
        <enum name="centerCrop" value="6" />
        <enum name="centerInside" value="7" />
    </attr>
    <attr name="adjustViewBounds" format="boolean" />
    <attr name="maxWidth" format="dimension" />
    <attr name="maxHeight" format="dimension" />
    <attr name="tint" format="color" />
    <attr name="baselineAlignBottom" format="boolean" />
    <attr name="cropToPadding" format="boolean" />
    <attr name="baseline" format="dimension" />
    <attr name="drawableAlpha" format="integer" />
    <attr name="tintMode" />
</declare-styleable>

Above code is a sample and it can cover most case in our development.

CoXier
  • 2,523
  • 8
  • 33
  • 60