I am getting pretty frustrated with all these official Android docs that conveniently gloss over the fact that even when you apply a Bitmap to an ImageView, the ImageView's dimensions are 0, 0, and yet you can't get the dimensions prior to mapping, either!
https://developer.android.com/training/displaying-bitmaps/load-bitmap.html
All these methods assume you already know fixed dimensions for the ImageView's height and width in terms of pixels, but this is almost useless because in practice you're supposed to either use dp units or layout_weight so things scale to the viewable region so things look right on various phones.
The only way, it would seem, to get the dimensions is to go to the trouble of inefficiently mapping the bitmap and then getting the dimensions that way, but even if you do, the dimensions will show up as 0 if you do imageView.getWidth()
or getHeight()
! You have to do a bunch of weird async stuff to wait until the dimensions somehow "settle" and THEN you can finally get the dimensions, but at this stage, what's the point when you've already wasted time doing an inefficient mapping?
Is there some well known workaround to all this that Google isn't explaining in the docs? How are you supposed to know the ImageView dimensions when you're not working with pixels in the XML? It's mind-boggling to me that this isn't documented more.
Here is a sample of the problem:
<ImageView
android:id="@+id/my_imageview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
I have this ImageView inside a DialogFragment. The idea is that I can map a Bitmap to this ImageView and it will fit inside the DialogFragment by means of something like myImageView.setImageBitmap(BitmapFactory.decodeFile(path_to_file));
, but this by itself is inefficient if the Bitmap is large.
However, in order to load the Bitmap efficiently, you need to already know the dimensions of the ImageView -- and in pixels! But you can't get the dimensions of the ImageView until you've already mapped the Bitmap inefficiently and waited for some kind of post-execute stage where the dimensions have settled in.
These are the methods I am using to do efficient mapping (assuming you already know the sizes -- it breaks if one of the dimensions is 0, so I added a fix). This code is from Google:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height == 0 || width == 0) {
return 0; //my fix
}
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromFilePath(String pathName, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(pathName, options);
}
And for example this does not work:
myImageView.post(new Runnable() {
@Override
public void run() {
int reqHeight = myImageView.getHeight(); //height = 0
int reqWidth = myImageView.getWidth(); //width = 528
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(picFullPath, options);
int realWidth = options.outWidth;
int realHeight = options.outHeight;
reqHeight = realHeight * reqWidth / realWidth; //reqHeight = 396, reqWidth = 528
Bitmap bm = decodeSampledBitmapFromFilePath(picFullPath, reqWidth, reqHeight);
myImageView.setImageBitmap(bm);
}
});
myImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int finalHeight = myImageView.getHeight(); //480!
int finalWidth = myImageView.getWidth(); //608!
}
});