Scale Image to Fill Imageview Width and Keep Aspect Ratio

Scale Image to fill ImageView width and keep aspect ratio

Without using any custom classes or libraries:

<ImageView
android:id="@id/img"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitCenter" />

scaleType="fitCenter" (default when omitted)

  • will make it as wide as the parent allows and up/down-scale as needed keeping aspect ratio.

scaleType="centerInside"

  • if the intrinsic width of src is smaller than parent width
    will center the image horizontally
  • if the intrinsic width of src is larger than parent width
    will make it as wide as the parent allows and down-scale keeping aspect ratio.

It doesn't matter if you use android:src or ImageView.setImage* methods and the key is probably the adjustViewBounds.

How to scale an Image in ImageView to keep the aspect ratio

  1. Yes, by default Android will scale your image down to fit the ImageView, maintaining the aspect ratio. However, make sure you're setting the image to the ImageView using android:src="..." rather than android:background="...". src= makes it scale the image maintaining aspect ratio, but background= makes it scale and distort the image to make it fit exactly to the size of the ImageView. (You can use a background and a source at the same time though, which can be useful for things like displaying a frame around the main image, using just one ImageView.)

  2. You should also see android:adjustViewBounds to make the ImageView resize itself to fit the rescaled image. For example, if you have a rectangular image in what would normally be a square ImageView, adjustViewBounds=true will make it resize the ImageView to be rectangular as well. This then affects how other Views are laid out around the ImageView.

    Then as Samuh wrote, you can change the way it default scales images using the android:scaleType parameter. By the way, the easiest way to discover how this works would simply have been to experiment a bit yourself! Just remember to look at the layouts in the emulator itself (or an actual phone) as the preview in Eclipse is usually wrong.

how to fit image to width and keep the aspect ratio in android

first in your layout add

android:scaleType="matrix"

to your imageView.

then in your java code add this:

ackground.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {

Bitmap backgroundBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.background_image);

float imageRatio = (float) backgroundBitmap.getWidth() / (float) backgroundBitmap.getHeight();

int imageViewWidth = background.getWidth();
int imageRealHeight = (int) (imageViewWidth / imageRatio);

Bitmap imageToShow = Bitmap.createScaledBitmap(backgroundBitmap, imageViewWidth, imageRealHeight, true);
background.setImageBitmap(imageToShow);

}
});

I will break it down for you:

at the java code you create a Bitmap object with the desired width (your imageView width) and set it to your imageView. but you need to make your imageView scaleType to matrix to prevent android from automatically scaling it!

Fit image into ImageView, keep aspect ratio and then resize ImageView to image dimensions?

(The answer was heavily modified after clarifications to the original question)

After clarifications:

This cannot be done in xml only. It is not possible to scale both the image and the ImageView so that image's one dimension would always be 250dp and the ImageView would have the same dimensions as the image.

This code scales Drawable of an ImageView to stay in a square like 250dp x 250dp with one dimension exactly 250dp and keeping the aspect ratio. Then the ImageView is resized to match the dimensions of the scaled image. The code is used in an activity. I tested it via button click handler.

Enjoy. :)

private void scaleImage(ImageView view) throws NoSuchElementException  {
// Get bitmap from the the ImageView.
Bitmap bitmap = null;

try {
Drawable drawing = view.getDrawable();
bitmap = ((BitmapDrawable) drawing).getBitmap();
} catch (NullPointerException e) {
throw new NoSuchElementException("No drawable on given view");
} catch (ClassCastException e) {
// Check bitmap is Ion drawable
bitmap = Ion.with(view).getBitmap();
}

// Get current dimensions AND the desired bounding box
int width = 0;

try {
width = bitmap.getWidth();
} catch (NullPointerException e) {
throw new NoSuchElementException("Can't find bitmap on given view/drawable");
}

int height = bitmap.getHeight();
int bounding = dpToPx(250);
Log.i("Test", "original width = " + Integer.toString(width));
Log.i("Test", "original height = " + Integer.toString(height));
Log.i("Test", "bounding = " + Integer.toString(bounding));

// Determine how much to scale: the dimension requiring less scaling is
// closer to the its side. This way the image always stays inside your
// bounding box AND either x/y axis touches it.
float xScale = ((float) bounding) / width;
float yScale = ((float) bounding) / height;
float scale = (xScale <= yScale) ? xScale : yScale;
Log.i("Test", "xScale = " + Float.toString(xScale));
Log.i("Test", "yScale = " + Float.toString(yScale));
Log.i("Test", "scale = " + Float.toString(scale));

// Create a matrix for the scaling and add the scaling data
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);

// Create a new bitmap and convert it to a format understood by the ImageView
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
width = scaledBitmap.getWidth(); // re-use
height = scaledBitmap.getHeight(); // re-use
BitmapDrawable result = new BitmapDrawable(scaledBitmap);
Log.i("Test", "scaled width = " + Integer.toString(width));
Log.i("Test", "scaled height = " + Integer.toString(height));

// Apply the scaled bitmap
view.setImageDrawable(result);

// Now change ImageView's dimensions to match the scaled image
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
params.width = width;
params.height = height;
view.setLayoutParams(params);

Log.i("Test", "done");
}

private int dpToPx(int dp) {
float density = getApplicationContext().getResources().getDisplayMetrics().density;
return Math.round((float)dp * density);
}

The xml code for the ImageView:

<ImageView a:id="@+id/image_box"
a:background="#ff0000"
a:src="@drawable/star"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_marginTop="20dp"
a:layout_gravity="center_horizontal"/>



Thanks to this discussion for the scaling code:

http://www.anddev.org/resize_and_rotate_image_-_example-t621.html



UPDATE 7th, November 2012:

Added null pointer check as suggested in comments

Android Studio ImageView Change Only Width and Maintain Aspect Ratio

Take the set width and divide it by the aspect ratio to get the height then set it like the code below

Display display = requireActivity().getWindowManager().getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics();
display.getMetrics(outMetrics);

Resources r = getResources();

float density = getResources().getDisplayMetrics().density;
//float dpHeight = outMetrics.heightPixels / density;
float dpWidth = outMetrics.widthPixels / density;

int widthPX = Math.round(TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, yourImageFixedWidthValue, r.getDisplayMetrics()));

float imageAspectRatio = (float) 335 / 217;
float imageWidth = widthPX;
float imageHeight = imageWidth / imageAspectRatio;

imageView.getLayoutParams().height = Math.round(TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, imageHeight, r.getDisplayMetrics()));
imageView.setAdjustViewBounds(true);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);

Scale ImageView to fit screen width/height while maintaining aspect ratio

It turned out to be a bit hard, and not possible out of the box. Many have similar problems.

I ended up porting @patrick-boos solution to .Net like so:

Extended ImageView Class

using Android.Content;
using Android.Util;
using Android.Widget;

namespace Nsa.BigBrotherUtility.Helpers
{
/// <summary>
/// DynamicImageView is a helper extension that overrides OnMeasure in order to scale the said image
/// to fit the entire width/or height of the parent container.
/// </summary>
public class DynamicImageView : ImageView
{
public DynamicImageView(Context context, IAttributeSet attributeSet) : base(context, attributeSet)
{

}

protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = MeasureSpec.GetSize(widthMeasureSpec);
int height = width * Drawable.IntrinsicHeight / Drawable.IntrinsicWidth;
SetMeasuredDimension(width, height);
}

}
}

My axml

<Nsa.BigBrotherUtility.Helpers.DynamicImageView
android:id="@+id/overlayImageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_vertical"
/>

The result

The 600x600 image now stretches to fill width of screen while maintaining aspect ratio

technical drawing being stretched to fit width of screen



Related Topics



Leave a reply



Submit