How to scale an Image in ImageView to keep the aspect ratio
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 thanandroid:background="..."
.src=
makes it scale the image maintaining aspect ratio, butbackground=
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.)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.
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 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);
How to maintain the aspect ratio of the image if imageview first stretch to fill parent
There can two possible workarounds even if you set the scale type fit_xy
1) 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.
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.
Related Topics
How to Send an Object from One Android Activity to Another Using Intents
How to Stop Edittext from Gaining Focus When an Activity Starts in Android
Firebase Android: Make Username Unique
Error in Launching Avd With Amd Processor
Fling Gesture Detection on Grid Layout
Creating a System Overlay Window (Always on Top)
How to Implement Onbackpressed() in Fragments
How to Get Current Time and Date in Android
How to Make an Imageview With Rounded Corners
Android Listview With Different Layouts For Each Row
Why 'Pageradapter::Notifydatasetchanged' Is Not Updating the View
This Activity Already Has an Action Bar Supplied by the Window Decor
How to Start New Activity on Button Click
Android Kotlin: Getting a Filenotfoundexception With Filename Chosen from File Picker
How to Make Links in a Textview Clickable
Is There an Addheaderview Equivalent For Recyclerview
Static Way to Get 'Context' in Android
How to Connect to a Specific Wi-Fi Network in Android Programmatically