Scale image keeping its aspect ratio in background drawable Scale image keeping its aspect ratio in background drawable android android

Scale image keeping its aspect ratio in background drawable


It is impossible to achieve manipulating background attribute within xml-files only. There are two options:

  1. You cut/scale the bitmap programmatically withBitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight,boolean filter) and set it as some View's background.

  2. You use ImageView instead of background placing it as the first layout's element and specify android:scaleType attribute for it:

    <RelativeLayout    android:layout_width="fill_parent"    android:layout_height="fill_parent" >    <ImageView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/backgrnd"        android:scaleType="centerCrop" />    ...    rest layout components here    ...</RelativeLayout>


There is an easy way to do this from the drawable:

your_drawable.xml

<?xml version="1.0" encoding="utf-8"?><layer-list xmlns:android="http://schemas.android.com/apk/res/android" >    <item android:drawable="@color/bg_color"/>    <item>        <bitmap            android:gravity="center|bottom|clip_vertical"            android:src="@drawable/your_image" />    </item></layer-list>

The only downside is that if there is not enough space, your image won't be fully shown, but it will be clipped, I couldn't find an way to do this directly from a drawable. But from the tests I did it works pretty well, and it doesn't clip that much of the image. You could play more with the gravity options.

Another way will be to just create an layout, where you will use an ImageView and set the scaleType to fitCenter.

Hope this information helps you achieve what you want.


I wanted to do something similar in my custom Drawable class.Here are the important pieces:

public class CustomBackgroundDrawable extends Drawable{    private Rect mTempRect = new Rect();    private Paint mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);    ...public void draw(@NonNull Canvas canvas){    Rect bounds = getBounds();    if (mBitmap != null ) {        if (mScaleType == ScaleType.SCALE_FILL) {            //bitmap scales to fill the whole bounds area (bitmap can be cropped)            if (bounds.height() > 0 && bounds.height() > 0) {                float scale = Math.min(mBitmap.getWidth()/(float)bounds.width(), mBitmap.getHeight()/(float)bounds.height());                float bitmapVisibleWidth = scale * bounds.width();                float bitmapVisibleHeight = scale * bounds.height();                mTempRect.set((int)(mBitmap.getWidth()-bitmapVisibleWidth)/2, 0, (int)(bitmapVisibleWidth+mBitmap.getWidth())/2, (int)bitmapVisibleHeight);                canvas.drawBitmap(mBitmap, mTempRect, bounds, mBitmapPaint);            }        } else if (mScaleType == ScaleType.SCALE_FIT) {            //bitmap scales to fit in bounds area            if (bounds.height() > 0 && bounds.height() > 0) {                float scale = Math.min((float)bounds.width()/mBitmap.getWidth(), (float)bounds.height()/mBitmap.getHeight());                float bitmapScaledWidth = scale * mBitmap.getWidth();                float bitmapScaledHeight = scale * mBitmap.getHeight();                int centerPadding = (int)(bounds.width()-bitmapScaledWidth)/2;                mTempRect.set(bounds.left + centerPadding, bounds.top, bounds.right - centerPadding, bounds.top+(int)bitmapScaledHeight);                canvas.drawBitmap(mBitmap, null, mTempRect, mBitmapPaint);            }        }    }}

With this approach you are flexible to apply any scale logic that you need