Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ImageView to scale to fixed height, but crop excess width

I would like my ImageView to scale in a particular fashion:

  • Scale so that the height of the image always fits the height of the ImageView
  • Crop any excess width

A picture speaks louder than a 1000 words, so here is a representation of how I want my ImageView to behave. Suppose it has a fixed height of say 100dp and suppose its width is match_parent.

enter image description here

Note that

  • on the phone layout, the image height is stretched, but the sides are cropped, akin to CROP_CENTER.
  • on the tablet layout, the image is also stretched to fit the ImageView height, behaving like FIT_CENTER

I suspect I need scaleType:matrix, but after that I'm lost. How can I make sure an image fits Y, but crops X?

like image 271
Maarten Avatar asked Jan 29 '14 08:01

Maarten


People also ask

Which attribute is important for ImageView other than width and height *?

Bookmark this question.

How do you change the size of a picture on android?

Tap the image you want to adjust. You can adjust the size of an image or rotate it: Resize: Touch and drag the squares along the edges. Rotate: Touch and drag the circle attached to the image.

What is adjustViewBounds?

android:adjustViewBounds—If set to true, the attribute adjusts the bounds of the ImageView control to maintain the aspect ratio of the image displayed through it.


4 Answers

In xml, use:

    android:scaleType="centerCrop"
    android:adjustViewBounds="true"

from & thanks to: https://stackoverflow.com/a/15600295/2162226

like image 196
Gene Bo Avatar answered Nov 08 '22 13:11

Gene Bo


With a little help from my friends Carlos Robles and pskink, came up with the following custom ImageView:

public class FitYCropXImageView extends ImageView {
    boolean done = false;

    @SuppressWarnings("UnusedDeclaration")
    public FitYCropXImageView(Context context) {
        super(context);
        setScaleType(ScaleType.MATRIX);
    }

    @SuppressWarnings("UnusedDeclaration")
    public FitYCropXImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setScaleType(ScaleType.MATRIX);
    }

    @SuppressWarnings("UnusedDeclaration")
    public FitYCropXImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setScaleType(ScaleType.MATRIX);
    }

    private final RectF drawableRect = new RectF(0, 0, 0,0);
    private final RectF viewRect = new RectF(0, 0, 0,0);
    private final Matrix m = new Matrix();
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (done) {
            return;//Already fixed drawable scale
        }
        final Drawable d = getDrawable();
        if (d == null) {
            return;//No drawable to correct for
        }
        int viewHeight = getMeasuredHeight();
        int viewWidth = getMeasuredWidth();
        int drawableWidth = d.getIntrinsicWidth();
        int drawableHeight = d.getIntrinsicHeight();
        drawableRect.set(0, 0, drawableWidth, drawableHeight);//Represents the original image
        //Compute the left and right bounds for the scaled image
        float viewHalfWidth = viewWidth / 2;
        float scale = (float) viewHeight / (float) drawableHeight;
        float scaledWidth = drawableWidth * scale;
        float scaledHalfWidth = scaledWidth / 2;
        viewRect.set(viewHalfWidth - scaledHalfWidth, 0, viewHalfWidth + scaledHalfWidth, viewHeight);

        m.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.CENTER /* This constant doesn't matter? */);
        setImageMatrix(m);

        done = true;

        requestLayout();
    }
}
like image 22
Maarten Avatar answered Nov 08 '22 12:11

Maarten


If you use scaleType:matrix you will need to create your own Matrix and asign it to the view by means of setImageMatrix(Matrix) or manually modify the matrix at hen onMEasure method of a customImageView.

public class MyImageView extends ImageView   {

 boolean done=false;

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if (done)
            return;

        final Drawable d = getDrawable();
        final int drawableW = d.getIntrinsicWidth();
        final int drawableH = d.getIntrinsicHeight();
        float ratio =  drawableW / drawableH;

        //int width = getMeasuredWidth();
        int height = getMeasuredHeight();

        float scale=height/drawableH;

          Matrix m = getImageMatrix();

          float[] f = new float[9];
          m.getValues(f);

          f[Matrix.MSCALE_X]=scale;
          f[Matrix.MSCALE_Y]=scale;

          m.setValues(f);  

        done = true;

        requestLayout();

    }

}
like image 44
Carlos Robles Avatar answered Nov 08 '22 13:11

Carlos Robles


    LinearLayout ll = new LinearLayout(this);
    ll.setOrientation(LinearLayout.VERTICAL);
    LayoutParams params;

    final ImageView iv0 = new ImageView(this);
    //iv0.setBackgroundColor(0xffff0000);
    params = new LayoutParams(LayoutParams.MATCH_PARENT, 100);
    ll.addView(iv0, params);

    final ImageView iv1 = new ImageView(this);
    //iv1.setBackgroundColor(0xff00ff00);
    params = new LayoutParams(60, 100);
    ll.addView(iv1, params);

    setContentView(ll);

    Runnable action = new Runnable() {
        @Override
        public void run() {
            Drawable d = getResources().getDrawable(R.drawable.layer0);
            int dw = d.getIntrinsicWidth();
            int dh = d.getIntrinsicHeight();
            RectF src = new RectF(0, 0, dw, dh);

            ImageView[] iviews = {iv0, iv1};
            for (int i = 0; i < iviews.length; i++) {
                ImageView iv = iviews[i];
                iv.setImageDrawable(d);
                iv.setScaleType(ScaleType.MATRIX);

                float h = iv.getHeight();
                float w = iv.getWidth();
                float cx = w / 2;
                float scale = h / dh;
                float deltaw = dw * scale / 2;
                RectF dst = new RectF(cx - deltaw, 0, cx + deltaw, h);
                Matrix m = new Matrix();
                m.setRectToRect(src, dst, ScaleToFit.FILL);
                iv.setImageMatrix(m);
            }
        }
    };
    iv1.post(action);
like image 40
pskink Avatar answered Nov 08 '22 13:11

pskink