49

What is the best way to retrieve the dimensions of the Drawable in an ImageView?

My ImageView has an Init-Method where I create the ImageView:

private void init() {
    coverImg = new ImageView(context);
    coverImg.setScaleType(ScaleType.FIT_START);
    coverImg.setImageDrawable(getResources().getDrawable(R.drawable.store_blind_cover));
    addView(coverImg);
}

At some point during the layout oder measure process I need the exact dimensions of the Drawable to adjust the rest of my Components around it.

coverImg.getHeight() and coverImg.getMeasuredHeight() don't return the results that I need and if I use coverImg.getDrawable().getBounds() I get the dimensions before it was scaled by the ImageView.

Thanks for your help!

Zain
  • 37,492
  • 7
  • 60
  • 84
Philipp Redeker
  • 3,848
  • 4
  • 26
  • 34

5 Answers5

54

Just tried this out and it works for me:

int finalHeight, finalWidth;
final ImageView iv = (ImageView)findViewById(R.id.scaled_image);
final TextView tv = (TextView)findViewById(R.id.size_label);
ViewTreeObserver vto = iv.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
    public boolean onPreDraw() {
        // Remove after the first run so it doesn't fire forever
        iv.getViewTreeObserver().removeOnPreDrawListener(this);
        finalHeight = iv.getMeasuredHeight();
        finalWidth = iv.getMeasuredWidth();
        tv.setText("Height: " + finalHeight + " Width: " + finalWidth);
        return true;
    }
});

The ViewTreeObserver will let you monitor the layout just prior to drawing it (i.e. everything has been measured already) and from here you can get the scaled measurements from the ImageView.

Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
  • ya it works but after oncreat() load is there any other way that we can get height or position in oncreat() – Khan Jun 02 '12 at 07:48
  • I like this solution, and it just about works for my needs. But for some reason onPrewDraw callback doesn't seem to ever stop firing. I simply logged the height and width to make sure. Any idea why? – jwBurnside Aug 12 '13 at 17:40
  • 2
    Override the View's `onsizeChanged()` method. You don't need to add pre-draw listeners. – D-Dᴙum Mar 31 '14 at 21:42
  • @Kerry That works only if it's a custom view you wrote yourself. – Kevin Coppock Mar 31 '14 at 21:46
  • `onSizechanged()` is called whether it's View or a developer's custom View. Either way you can still override it, just call through to the super if it's not a custom view. – D-Dᴙum Mar 31 '14 at 22:02
  • @Kerry You can't override that method unless you're subclassing the View. – Kevin Coppock Mar 31 '14 at 22:03
  • It's a pain but there's nothing stopping you doing that. – D-Dᴙum Mar 31 '14 at 22:09
  • Sure, it's a solution in some cases when you need to do something with a custom view, but the pre-draw listener is a solution for any view. – Kevin Coppock Mar 31 '14 at 22:10
  • Yes fair point. I should read the question with more care. I withdraw my criticism. Sorry! – D-Dᴙum Mar 31 '14 at 22:31
  • @Kerry No problem :) I think that's definitely the better solution for the case where a custom View needs to change how it renders its own content. – Kevin Coppock Mar 31 '14 at 22:32
  • There is a typo in your example: tv.getViewTreeObserver().removeOnPreDrawListener(this); but we should remove listener from "iv" not from "tv". – toxa_xa Oct 10 '14 at 04:10
  • This answer is being [discussed on meta](http://meta.stackoverflow.com/questions/327523/same-answer-by-same-user-posted-in-two-questions?cb=1), – Jean-François Corbett Jul 07 '16 at 12:00
50

Call getIntrinsicHeight and getIntrinsicWidth on the drawable.

public int getIntrinsicHeight ()

Since: API Level 1

Return the intrinsic height of the underlying drawable object. Returns -1 if it has no intrinsic height, such as with a solid color.

public int getIntrinsicWidth ()

Since: API Level 1

Return the intrinsic width of the underlying drawable object.

Returns -1 if it has no intrinsic width, such as with a solid color.

http://developer.android.com/reference/android/graphics/drawable/Drawable.html#getIntrinsicHeight()

This is the size of the original drawable. I think this is what you want.

David Passmore
  • 6,089
  • 4
  • 46
  • 70
Pedro Loureiro
  • 11,436
  • 2
  • 31
  • 37
  • I am facing the same problem. But intrinsic height and width are different on different sized devices even though the underlying png is of course the same size! How can that be? Where is the documentation for "intrinsic"? – Zordid Sep 03 '11 at 11:30
  • 15
    In fact, looking at Android's source code: these intrinsic values are affected by the target density, so they are definitely NOT the dimensions of the image! – Zordid Sep 03 '11 at 11:33
  • So? What is the trick to get the dimensions of the image then? – cagcak Oct 11 '14 at 15:27
  • 1
    @Zordid Can you make a reference, because based on experimentation this is the actual dimensions of the original image, in other word the size in dp units NOT px. – Warpzit Feb 04 '16 at 20:48
  • @Zordid if you store image with width 120px in xxhdpi folder, intristicWidth will be 120 on xxhdpi device, however it will be 60 on hdpi device. Because autoscaling of course. – stevo.mit Sep 12 '16 at 06:41
24

The most reliable and powerful way to get drawable dimensions for me has been to use BitmapFactory to decode a Bitmap. It's very flexible - it can decode images from a drawable resource, file, or other different sources.

Here's how to get dimensions from a drawable resource with BitmapFactory:

BitmapFactory.Options o = new BitmapFactory.Options();
o.inTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
Bitmap bmp = BitmapFactory.decodeResource(activity.getResources(),
                                               R.drawable.sample_image, o);
int w = bmp.getWidth();
int h = bmp.getHeight();

Be careful if you use multiple density drawable folders under res, and make sure you specify inTargetDensity on your BitmapFactory.Options to get the drawable of the density you want.

AndyW
  • 1,431
  • 16
  • 22
ubzack
  • 1,878
  • 16
  • 16
11

Efficient way to get Width & Height of Drawable:

Drawable drawable = getResources().getDrawable(R.drawable.ic_home);
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
Log.i("Drawable dimension : W-H", width+"-"+height);

Hope this will help you.

Hiren Patel
  • 52,124
  • 21
  • 173
  • 151
6

this solved my problem. It decode the size of image boundary without really load the whole image.

BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeResource(this.getResources(), R.drawable.img , o);
int w = o.outWidth;
int h = o.outHeight;
Nevin Chen
  • 1,815
  • 16
  • 19
  • This answer is an inferior and syntactically incorrect copy of ubzack's [answer](https://stackoverflow.com/a/8917221/3153792). – corsair992 Nov 24 '14 at 02:18
  • @corsair992 Thanks for the note :) I just found I didn't paste my complete code. That's why you feel it's copied from others' answer :) – Nevin Chen Nov 24 '14 at 05:58
  • OK, but you should add a comma before the last parameter of the `decodeResource()` method in order to make it syntactically correct. – corsair992 Nov 24 '14 at 16:15
  • 2
    This is the best answer to this portion of noteme's question: "retrieve the dimensions of the Drawable". It is less resource intensive: refer documentation "Setting the inJustDecodeBounds property to true while decoding avoids memory allocation" http://developer.android.com/training/displaying-bitmaps/load-bitmap.html – rayzinnz May 29 '15 at 04:13
  • It is definitely less resource intensive, which is an important consideration if the reason you want to resize the image is because you don't want to run in to OutOfMemory errors. However, it does not answer the question - the OP wishes to know the size of the drawable after it has been scaled inside the ImageView. I +1 it in the hope that it might be useful to someone else who landed up at this page to whom getting the actual unscaled drawable's dimensions was sufficient, but frankly, this is not the right answer. – Abraham Philip Jan 06 '16 at 16:58