Maarten Maarten - 5 months ago 55
Android Question

ImageView to scale to fixed height, but crop excess width

I would like my

to scale in a particular fashion:

  • Scale so that the height of the image always fits the height of the

  • Crop any excess width

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

enter image description here

Note that

  • on the phone layout, the image height is stretched, but the sides are cropped, akin to

  • on the tablet layout, the image is also stretched to fit the
    height, behaving like

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


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;

    public FitYCropXImageView(Context context) {

    public FitYCropXImageView(Context context, AttributeSet attrs) {
        super(context, attrs);

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

    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();
    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? */);

        done = true;