Get the ID of a drawable in ImageView

I think if I understand correctly this is what you are doing.

ImageView view = (ImageView) findViewById(R.id.someImage);
view.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
        ImageView imageView = (ImageView) view;
        assert(R.id.someImage == imageView.getId());

        switch(getDrawableId(imageView)) {
            case R.drawable.foo:
                imageView.setDrawableResource(R.drawable.bar);
                break;
            case R.drawable.bar:
            default:
                imageView.setDrawableResource(R.drawable.foo);
            break;
        }
    });

Right? So that function getDrawableId() doesn't exist. You can't get a the id that a drawable was instantiated from because the id is just a reference to the location of data on the device on how to construct a drawable. Once the drawable is constructed it doesn't have a way to get back the resourceId that was used to create it. But you could make it work something like this using tags

ImageView view = (ImageView) findViewById(R.id.someImage);
view.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
        ImageView imageView = (ImageView) view;
        assert(R.id.someImage == imageView.getId());

        // See here
        Integer integer = (Integer) imageView.getTag();
        integer = integer == null ? 0 : integer;

        switch(integer) {
        case R.drawable.foo:
            imageView.setDrawableResource(R.drawable.bar);
            imageView.setTag(R.drawable.bar);
            break;
        case R.drawable.bar:
        default:
            imageView.setDrawableResource(R.drawable.foo);
            imageView.setTag(R.drawable.foo);
            break;
        }
    });

I answered something like this in another question already, but will change it just a little for this one.

Unfortunately, there is no getImageResource() or getDrawableId(). But, I created a simple workaround by using the ImageView tags.

In onCreate():

imageView0 = (ImageView) findViewById(R.id.imageView0);
imageView1 = (ImageView) findViewById(R.id.imageView1);
imageView2 = (ImageView) findViewById(R.id.imageView2);

imageView0.setTag(R.drawable.apple);
imageView1.setTag(R.drawable.banana);
imageView2.setTag(R.drawable.cereal);

Then, if you like, you can create a simple function to get the drawable id:

private int getDrawableId(ImageView iv) {
    return (Integer) iv.getTag();
}

Too easy.


Digging StackOverflow for answers on the similar issue I found people usually suggesting 2 approaches:

  • Load a drawable into memory and compare ConstantState or bitmap itself to other one.
  • Set a tag with drawable id into a view and compare tags when you need that.

Personally, I like the second approach for performance reason but tagging bunch of views with appropriate tags is painful and time consuming. This could be very frustrating in a big project. In my case I need to write a lot of Espresso tests which require comparing TextView drawables, ImageView resources, View background and foreground. A lot of work.

So I eventually came up with a solution to delegate a 'dirty' work to the custom inflater. In every inflated view I search for a specific attributes and and set a tag to the view with a resource id if any is found. This approach is pretty much the same guys from Calligraphy used. I wrote a simple library for that: TagView

If you use it, you can retrieve any of predefined tags, containing drawable resource id that was set in xml layout file:

TagViewUtils.getTag(view, ViewTag.IMAGEVIEW_SRC.id)
TagViewUtils.getTag(view, ViewTag.TEXTVIEW_DRAWABLE_LEFT.id)
TagViewUtils.getTag(view, ViewTag.TEXTVIEW_DRAWABLE_TOP.id)
TagViewUtils.getTag(view, ViewTag.TEXTVIEW_DRAWABLE_RIGHT.id)
TagViewUtils.getTag(view, ViewTag.TEXTVIEW_DRAWABLE_BOTTOM.id)
TagViewUtils.getTag(view, ViewTag.VIEW_BACKGROUND.id)
TagViewUtils.getTag(view, ViewTag.VIEW_FOREGROUND.id)

The library supports any attribute, actually. You can add them manually, just look into the Custom attributes section on Github. If you set a drawable in runtime you can use convenient library methods:

setImageViewResource(ImageView view, int id)

In this case tagging is done for you internally. If you use Kotlin you can write a handy extensions to call view itself. Something like this:

fun ImageView.setImageResourceWithTag(@DrawableRes int id) {
    TagViewUtils.setImageViewResource(this, id)
}

You can find additional info in Tagging in runtime


As of today, there is no support on this function. However, I found a little hack on this one.

 imageView.setImageResource(R.drawable.ic_star_black_48dp);
 imageView.setTag(R.drawable.ic_star_black_48dp);

So if you want to get the ID of the view, just get it's tag.

if (imageView.getTag() != null) {
   int resourceID = (int) imageView.getTag();

   //
   // drawable id.
   //   
}