There are various XML attributes for ImageView to scale its content , and various layout views that allow to place views and set their sizes.
However, I can't figure out how to scale an imageView nicely on some cases.
An example of it is to put the ImageView on the bottom (of a frameLayout, for example) , scale its width as much as possible, and still keep the aspect ratio (without cropping).
None of the combinations I've found worked, including various ScaleType values, adjustViewBounds, gravity ,...
It seems as if ImageView misses some important ScaleType values.
So far, the only solution that worked for me, is to set the imageView to the bottom (using the gravity set to bottom and center-horizontal), and use code, similar to this:
final ImageView logoBackgroundImageView = ...;
final LayoutParams layoutParams = logoBackgroundImageView.getLayoutParams();
final Options bitmapOptions = ImageService.getBitmapOptions(getResources(), R.drawable.splash_logo);
final int screenWidth = getResources().getDisplayMetrics().widthPixels;
layoutParams.height = bitmapOptions.outHeight * screenWidth / bitmapOptions.outWidth;
logoBackgroundImageView.setLayoutParams(layoutParams);
This usually works , and doesn't need much changes to make it work for when it's not in full screen, but I wonder if there is a simpler way.
It might not work in case the height gets to be too large, so you might want to change it so that if that's happening, you set the width to be smaller to allow everything fit the container.
Is there a solution or a library that fixes the various issues related to the ImageView ?
EDIT: here's a sample image of what I'm trying to do, this time, within a vertical LinearLayout that bounds the ImageView in the middle, between 2 other views:
As you can see, on some (or all?) of the previews, the middle image is aligned to the right instead of staying on the middle (horizontal).
I want it to take all the space it got and scale (keeping aspect ratio), and yet be aligned to the bottom of the space that it has.
here's a sample XML of one combination I've tried :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF339AE2">
<View
android:layout_width="match_parent"
android:id="@+id/topView"
android:layout_alignParentTop="true"
android:layout_height="100dp"
android:background="#FF00ff00"
/>
<FrameLayout
android:layout_below="@+id/topView"
android:layout_width="match_parent"
android:layout_centerHorizontal="true"
android:layout_above="@+id/bottomView"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:background="#FFffff00"
android:layout_gravity="bottom|center_horizontal"
android:src="@android:drawable/sym_def_app_icon"
android:scaleType="fitEnd"
android:layout_height="match_parent"
/>
</FrameLayout>
<View
android:background="#FFff0000"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:id="@+id/bottomView"
android:layout_width="match_parent"
android:layout_height="100dp"/>
</RelativeLayout>
Again, note that I've tried multiple combinations, but none of them worked, so if you suggest something to change in the XML, please try it out first. Also note that the above is a POC (to make it easy to read).
BTW, the workaround I've suggested works on some (or most?) cases, but not all. You can notice it by just rotating your device. Maybe there is a way to fix it, or extend from ImageView to provide the extra case.
You need a combination of three attributes:
android:layout_height="wrap_content"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
The adjustViewBounds
attribute is needed because ImageView
measures itself to match the original dimensions of the drawable by default, without regard to any scaling performed according to the scale type.
You can use is custom FitWidthAtBottomImageView
to achieve this code:
public class FitWidthAtBottomImageView extends ImageView {
public FitWidthAtBottomImageView(Context context) {
super(context);
}
public FitWidthAtBottomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FitWidthAtBottomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public FitWidthAtBottomImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onDraw(Canvas canvas) {
int i = getWidth() - getPaddingLeft() - getPaddingRight();
int j = getHeight() - getPaddingTop() - getPaddingBottom();
if (getBackground() != null) {
getBackground().draw(canvas);
}
if (getDrawable() != null && getDrawable() instanceof BitmapDrawable) {
Bitmap bitmap = ((BitmapDrawable) getDrawable()).getBitmap();
int h = bitmap.getHeight() * i / bitmap.getWidth();
canvas.drawBitmap(bitmap, null, new RectF(getPaddingLeft(), getPaddingTop() + j - h, getPaddingLeft() + i, getHeight() - getPaddingBottom()), null);
} else {
super.onDraw(canvas);
}
}
}
by manually draw the bottom aligned image that you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With