Android – How to make an Image as large as possible while maintaining aspect ratio

androidandroid-layoutimageview

I have an image which is smaller than the container I would like it to fit inside of. I would like the image to stretch, keeping it's aspect ratio, to it's largest possible size.

To illustrate this problem:

<ImageView  android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:src="@drawable/thumbnail"
            android:scaleType="fitXY"
            android:adjustViewBounds="true"/>

The ImageView above would be stretched to fill the width of the container. The @drawable it contained would also stretch along the x axis to fit the width of ImageView which is perfect. The problem however is that the dimension labelled wrap_content, in this case height, remains the same size as the @drawables initial height.

I have read the documentation regarding ScaleType here and can't find the answer there.

The following image describes the above code:

enter image description here enter image description here

  Current behaviour               Desired Behaviour

Edit

An ImageView given scaleType="fitCenter" will accurately expand/shrink the @drawable inside of it to grow as large as possible while retaining it's aspect ratio.

The ImageViews dimensions are defined before the @drawable is scaled in any way. The ImageView dimensions are not effected by scaling of it's contained @drawable.

Best Answer

XML

The only solution to this in XML is to use "match_parent" or a discrete maximum value instead of "wrap_content" where possible. This will ensure the ImageView is the correct size, which will then meaning adding scaleType="fitCenter" will ensure the @drawable will then scale correctly.

Programatically

It's ugly, but you can resize the ImageView after it's dimensions have been given discrete values:

    final ImageView thumbnailView = (ImageView) toReturn.findViewById(R.id.thumbnail);  

    ViewTreeObserver thumbnailViewVto = thumbnailView.getViewTreeObserver();
    thumbnailViewVto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        private boolean changed = false;
        @Override
        public void onGlobalLayout() {
            if(!changed) {
                Drawable image = getResources().getDrawable(R.drawable.thumbnail);
                float heighToWidthRatio = image.getIntrinsicWidth()/image.getIntrinsicHeight();
                int height = thumbnailView.getHeight();

                thumbnailView.setLayoutParams(
                        new LayoutParams(
                                (int) (height * heighToWidthRatio), height));
                changed = true;
            }
        }
    });

EDIT

    final ImageView thumbnailView = (ImageView) toReturn.findViewById(R.id.thumbnail);  

    thumbnailView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

        @Override
        public void onGlobalLayout() {
            // Remove the GlobalOnLayout Listener so it only fires once.
            thumbnailView.getViewTreeObserver().removeGlobalOnLayoutListener(this)

            // Find the images Height to Width ratio
            Drawable image = getResources().getDrawable(R.drawable.thumbnail);
            float heighToWidthRatio = image.getIntrinsicWidth()/image.getIntrinsicHeight();

            // Use this ratio to discover the ratio of the ImageView to allow it to perfectly contain the image.
            int height = thumbnailView.getHeight();
            thumbnailView.setLayoutParams(new LayoutParams(
                                (int) (height * heighToWidthRatio), height));
        }
    });
Related Topic