-4

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!
        }
    });

2 Answers2

0

You Should get height and Width of view after inflate any view from XML or Dynamically and then use bellow code to get rendered view height and width :

        imageView.measure(0,0);
        imageView.getMeasuredHeight();
        imageView.getMeasuredWidth();

But Above method may given 0 for height and width , if you are not passing any height and width from XML or you are not used any relative property in Relative layout

Chetan Joshi
  • 5,582
  • 4
  • 30
  • 43
  • Yes, the 0's are the big problem – user7460835 Jan 24 '17 at 06:51
  • But in your view their must be an predefined area there in which you want to show image . So you should calculate parentage Width height and width from your screen size and them applied for all screen size and pass into google "Loading Large Bitmaps Efficiently" approach to get scaled bitmap. – Chetan Joshi Jan 24 '17 at 07:38
0

I use this approach when I need to load bitmap after I know ImageView size:

    myImageView.post(new Runnable() {
            @Override
            public void run() {
                int requiredHeight = myImageView.getHeight(); //height is ready, but is 0 - not calculated.
                int requiredWidth = myImageView.getWidth(); //width ready


                final BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true;
                BitmapFactory.decodeFile(pathName, options);
                int realWidth = option.outWidth;
                int realHeight = option.outHeight;

                //calculating required Height
                requiredHeight = realHeight / realWidth * requiredWidth;

                //now we have both - required height and width.

                Bitmap bm = decodeSampledBitmapFromFilePath(pathName, requiredWidth, requiredHeight);


                myImageView.setImageBitmap(bm);
            }
        });
Vladyslav Matviienko
  • 10,610
  • 4
  • 33
  • 52
  • I appreciate the answer but I do not believe this solves the problem either. The height at this point is 0 and the width is 528 (whereas if you were to map it, the height ends up being something like 480 and the width 608). See also the "efficient mapping" code in the original post from Google, which breaks if one of the dimensions is 0 – user7460835 Jan 24 '17 at 07:17
  • @user7460835, in short, knowing required width, and image real width and height, you can easily calculate required height. So I still don't see any problem. – Vladyslav Matviienko Jan 24 '17 at 07:22
  • @user7460835 `requiredHeight = realHeight / realWidth * requiredWidth;` – Vladyslav Matviienko Jan 24 '17 at 07:26
  • @user7460835, ok, looks like I have no other choice except providing full working code. – Vladyslav Matviienko Jan 24 '17 at 07:27
  • In this case: `realHeight = 480` and `realWidth = 640` (going from the outHeight and outWidth properties of BitmapFactory.Options for the source file), so the quotient is `.75`. The required width premapping is `528`, implying a `requiredHeight` around `396`, but in reality `requiredWidth` becomes `608` and `requiredWidth` is `456` but then in practice it's `480` – user7460835 Jan 24 '17 at 07:31
  • Yes, your edit is nearly char-for-char what I've written on my end (although with a different ratio because that will go to 0 due to floor division); `reqHeight = realHeight * reqWidth / realWidth;` – user7460835 Jan 24 '17 at 07:34
  • So for example in your code `requiredHeight = 396` and `requiredWidth = 528` (after fixing the equation) but then when you get the real dimensions later, they are different. – user7460835 Jan 24 '17 at 07:39