Stretch Image to Fit

2020-02-03 07:14发布

问题:

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).

<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

回答1:

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" />


回答2:

android:adjustViewBounds="true" does the job!



回答3:

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" />


回答4:

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

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



回答5:

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);
    }
}


回答6:

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));


回答7:

Try android:scaleType="CENTER_INSIDE"

Android docs here



回答8:

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?