24

The src should stretch its width to match_parent, while keeping aspect ratio. When the image is larger than the parent, it scales down correctly. But when the image is smaller, it does not scale up. (illustration shows desired behavior).

enter image description here

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:id="@+id/banner"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="fitCenter"
        android:adjustViewBounds="true"
        android:src="@drawable/foo"
        />

</RelativeLayout>


Using ScaleType.fitXY stretches the width only

Matt
  • 5,461
  • 7
  • 36
  • 43
  • Have you tried using scale type fitEnd or fitStart? That worked for me to solve a similar problem. When I used fitEnd, I did not set the property adjustViewBounds. – blackcj Sep 05 '13 at 17:04

8 Answers8

25

I believe that is not possible, at least not with the options provided by scaleType attribute.
Your best option in this case is to use centerCrop, but only the center of the picture will be visible.

However, if you are not ok with this option, then you could scale the image programatically without loosing aspect ratio. In order to achieve this you'll need to calculate a scale factor based on the screen width, and then use this scale factor to know the new height of the image.

Like this:

ImageView imageView = (ImageView)findViewById(R.id.imageView);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.foo);

int imageWidth = bitmap.getWidth();
int imageHeight = bitmap.getHeight();

int newWidth = getScreenWidth(); //this method should return the width of device screen.
float scaleFactor = (float)newWidth/(float)imageWidth;
int newHeight = (int)(imageHeight * scaleFactor);

bitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
imageView.setImageBitmap(bitmap);

Also, you'll need to adjust the declaration of ImageView in layout file:

<ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
Andy Res
  • 15,963
  • 5
  • 60
  • 96
  • Thanks, that did the trick. I had a feeling the solution would be outside of xml – Matt Sep 05 '13 at 17:59
  • 1
    @Andy, what context is your code written in? I can't find getScreenWidth() in Context or Activity. –  Oct 20 '13 at 10:42
  • @YekhezkelYovel, that method you should create yourself. Its implementation was beyound the scope of the answer. – Andy Res Oct 20 '13 at 15:44
  • I get it now. I'd just put the comment there to make it clear that you are leaving something undone, but that's no big deal. –  Oct 20 '13 at 16:00
11

android:adjustViewBounds="true" does the job!

ViliusK
  • 11,345
  • 4
  • 67
  • 71
9

use this MainImage.setScaleType(ImageView.ScaleType.FIT_XY);

OR you can simply add android:scaleType="fitXY" in xml.

ELITE
  • 5,815
  • 3
  • 19
  • 29
halo89
  • 101
  • 1
  • 1
6
setContentView(R.layout.activity_main);

ImageView imageView = (ImageView)findViewById(R.id.imageView);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);

int imageWidth = bitmap.getWidth();
int imageHeight = bitmap.getHeight();

DisplayMetrics metrics = this.getResources().getDisplayMetrics();

int newWidth = metrics.widthPixels;
float scaleFactor = (float)newWidth/(float)imageWidth;
int newHeight = (int)(imageHeight * scaleFactor);

bitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
imageView.setImageBitmap(bitmap);

LAYOUT

<ImageView
    android:id="@+id/imageView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:scaleType="centerInside"
    android:src="@drawable/image" />
Pedro Lobito
  • 94,083
  • 31
  • 258
  • 268
3

Does:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/banner"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="centerCrop"
        android:adjustViewBounds="true"
        android:src="@drawable/foo" />
</RelativeLayout>

Not do what you want?

yarian
  • 5,922
  • 3
  • 34
  • 48
2

I usually use the following class in XML when I want this behavior:

Of course I tweak it sometimes according to some requirements. But I find it easier to change the class from ImageView to a different class in XML instead of java code in the context of the view.

package shush.android.util;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.widget.ImageView;

/**
 * @author Sherif elKhatib
 *
 * ImageView Class that maintains the width of the view and changes height to keep the aspect ratio.
 */
public class AspectImageView extends ImageView {

    public AspectImageView(Context context) {
        super(context);
    }

    public AspectImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AspectImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if(getBackground() == null || getBackground().getIntrinsicHeight()==0 || getBackground().getIntrinsicWidth()==0) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            return;
        }
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = width * getBackground().getIntrinsicHeight() / getBackground().getIntrinsicWidth();
        setMeasuredDimension(width, height);
    }
    @SuppressLint("NewApi")
    @SuppressWarnings("deprecation")
    @Override
    public void setImageBitmap(Bitmap bm) {
        if(bm == null)
            return;
        BitmapDrawable bd = new BitmapDrawable(getContext().getResources(), bm);
        if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN)
            setBackground(bd);
        else
            setBackgroundDrawable(bd);
    }
}
Sherif elKhatib
  • 45,786
  • 16
  • 89
  • 106
2

Combining the two brilliant answers (this one and this one) into a quick solution. I hope this saves someone unnecessary research time!

private Bitmap getScaledBitmap(int resource) {
    DisplayMetrics displaymetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    int width = displaymetrics.widthPixels;

    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resource);

    float scaleFactor = (float) width / (float) bitmap.getWidth();
    int newHeight = (int) (bitmap.getHeight() * scaleFactor);

    return Bitmap.createScaledBitmap(bitmap, width, newHeight, true);
}

Use it like this:

imageView.setImageBitmap(getScaledBitmap(R.drawable.banner_home_2));
Community
  • 1
  • 1
Oleksiy
  • 37,477
  • 22
  • 74
  • 122
1

Try android:scaleType="CENTER_INSIDE"

Android docs here

Dan Schnau
  • 1,505
  • 14
  • 17
  • No luck. That makes the view just large enough to fit the image vertically, leaving space on both sides – Matt Aug 20 '13 at 22:05