Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Custom Android ImageView for top-crop scaling of the contained drawable.
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* Created by chris on 7/27/16.
*/
public class TopCropImageView extends ImageView {
public TopCropImageView(Context context) {
super(context);
init();
}
public TopCropImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TopCropImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public TopCropImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
recomputeImgMatrix();
}
@Override
protected boolean setFrame(int l, int t, int r, int b) {
recomputeImgMatrix();
return super.setFrame(l, t, r, b);
}
private void init() {
setScaleType(ScaleType.MATRIX);
}
private void recomputeImgMatrix() {
final Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
final Matrix matrix = getImageMatrix();
float scale;
final int viewWidth = getWidth() - getPaddingLeft() - getPaddingRight();
final int viewHeight = getHeight() - getPaddingTop() - getPaddingBottom();
final int drawableWidth = drawable.getIntrinsicWidth();
final int drawableHeight = drawable.getIntrinsicHeight();
if (drawableWidth * viewHeight > drawableHeight * viewWidth) {
scale = (float) viewHeight / (float) drawableHeight;
} else {
scale = (float) viewWidth / (float) drawableWidth;
}
matrix.setScale(scale, scale);
setImageMatrix(matrix);
}
}
@Wavesonics

This comment has been minimized.

Show comment Hide comment
@Wavesonics

Wavesonics Nov 8, 2012

Great snippet, works perfectly!

Great snippet, works perfectly!

@suda

This comment has been minimized.

Show comment Hide comment
@suda

suda Jan 14, 2013

Looks like it's missing

import android.content.Context;

import :)

suda commented Jan 14, 2013

Looks like it's missing

import android.content.Context;

import :)

@arriolac

This comment has been minimized.

Show comment Hide comment
@arriolac

arriolac Jan 18, 2013

@suda, thanks!

Owner

arriolac commented Jan 18, 2013

@suda, thanks!

@idnael

This comment has been minimized.

Show comment Hide comment
@idnael

idnael May 17, 2013

your soluton worked for me until I change the device orientation!
Then setFrame is called with the previous view width value.
SO I think maybe I should put the change matrix code in another method?

idnael commented May 17, 2013

your soluton worked for me until I change the device orientation!
Then setFrame is called with the previous view width value.
SO I think maybe I should put the change matrix code in another method?

@gbenson-nflx

This comment has been minimized.

Show comment Hide comment
@gbenson-nflx

gbenson-nflx May 20, 2014

This was helpful but I also had to override onLayout() to get the scaling matrix to update properly for layout changes. Using setFrame() was not enough given my usage.

e.g.:

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        recomputeImgMatrix();
    }

This was helpful but I also had to override onLayout() to get the scaling matrix to update properly for layout changes. Using setFrame() was not enough given my usage.

e.g.:

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        recomputeImgMatrix();
    }
@ErNaveen

This comment has been minimized.

Show comment Hide comment
@ErNaveen

ErNaveen Aug 13, 2014

need imageview with zoom in and out with croping can i use it

need imageview with zoom in and out with croping can i use it

@followztx

This comment has been minimized.

Show comment Hide comment
@followztx

followztx Dec 30, 2014

@gbenson-nflx thanks .

@gbenson-nflx thanks .

@enknamel

This comment has been minimized.

Show comment Hide comment
@enknamel

enknamel Feb 2, 2015

@gbenson-nflx My images were not showing up at all until I added your code. Very strange. Though I am using this as a background for a layout in a scrollview so something wonky is going on.

enknamel commented Feb 2, 2015

@gbenson-nflx My images were not showing up at all until I added your code. Very strange. Though I am using this as a background for a layout in a scrollview so something wonky is going on.

@cesards

This comment has been minimized.

Show comment Hide comment
@cesards

cesards Feb 17, 2015

I developed a library for this purpose. I think it's a litte bit late but you could add the dependency and replace it ;-)

https://github.com/cesards/CropImageView

Have fun!!

cesards commented Feb 17, 2015

I developed a library for this purpose. I think it's a litte bit late but you could add the dependency and replace it ;-)

https://github.com/cesards/CropImageView

Have fun!!

@arriolac

This comment has been minimized.

Show comment Hide comment
@arriolac

arriolac Mar 11, 2015

@gbenson-nflx updated the gist from the snippet you shared. Thanks!

Owner

arriolac commented Mar 11, 2015

@gbenson-nflx updated the gist from the snippet you shared. Thanks!

@zelin

This comment has been minimized.

Show comment Hide comment
@zelin

zelin Apr 8, 2015

Great snippet ^^

zelin commented Apr 8, 2015

Great snippet ^^

@adriancosma

This comment has been minimized.

Show comment Hide comment
@adriancosma

adriancosma May 2, 2015

I would like to have the imageview crop the top center part of the image, now seems that is top left. How can I change the code to obtain a crop centered and not left aligned? Thanks!

I would like to have the imageview crop the top center part of the image, now seems that is top left. How can I change the code to obtain a crop centered and not left aligned? Thanks!

@briandilley

This comment has been minimized.

Show comment Hide comment
@briandilley

briandilley Jun 24, 2015

to center it:

    private void recomputeImgMatrix() {
        final Matrix matrix = getImageMatrix();

        float scale;
        final int viewWidth = getWidth() - getPaddingLeft() - getPaddingRight();
        final int viewHeight = getHeight() - getPaddingTop() - getPaddingBottom();
        final int drawableWidth = getDrawable().getIntrinsicWidth();
        final int drawableHeight = getDrawable().getIntrinsicHeight();

        if (drawableWidth * viewHeight > drawableHeight * viewWidth) {
            scale = (float) viewHeight / (float) drawableHeight;
        } else {
            scale = (float) viewWidth / (float) drawableWidth;
        }

        matrix.setScale(scale, scale);
        if ((drawableWidth * scale) > viewWidth) {
            float tr = -(((drawableWidth * scale) - viewWidth) / 2);
            matrix.postTranslate(tr, 0);
        }
        setImageMatrix(matrix);
    }

to center it:

    private void recomputeImgMatrix() {
        final Matrix matrix = getImageMatrix();

        float scale;
        final int viewWidth = getWidth() - getPaddingLeft() - getPaddingRight();
        final int viewHeight = getHeight() - getPaddingTop() - getPaddingBottom();
        final int drawableWidth = getDrawable().getIntrinsicWidth();
        final int drawableHeight = getDrawable().getIntrinsicHeight();

        if (drawableWidth * viewHeight > drawableHeight * viewWidth) {
            scale = (float) viewHeight / (float) drawableHeight;
        } else {
            scale = (float) viewWidth / (float) drawableWidth;
        }

        matrix.setScale(scale, scale);
        if ((drawableWidth * scale) > viewWidth) {
            float tr = -(((drawableWidth * scale) - viewWidth) / 2);
            matrix.postTranslate(tr, 0);
        }
        setImageMatrix(matrix);
    }
@Bapho

This comment has been minimized.

Show comment Hide comment
@Bapho

Bapho Aug 11, 2015

be aware that the drawable can be null in recomputeImgMatrix().

Bapho commented Aug 11, 2015

be aware that the drawable can be null in recomputeImgMatrix().

@OMID9191

This comment has been minimized.

Show comment Hide comment
@OMID9191

OMID9191 Aug 11, 2015

hi:
i import this class to my project ...
how to use for another class and use for image view ?

hi:
i import this class to my project ...
how to use for another class and use for image view ?

@OMID9191

This comment has been minimized.

Show comment Hide comment
@OMID9191

OMID9191 Aug 12, 2015

pls any tell me

pls any tell me

@spartacus777

This comment has been minimized.

Show comment Hide comment
@spartacus777

spartacus777 Sep 7, 2015

Worked perfectly in conjunction with UIL (universal image loader)

Worked perfectly in conjunction with UIL (universal image loader)

@cesards

This comment has been minimized.

Show comment Hide comment
@cesards

cesards Oct 20, 2015

This snippet has a bug in devices with API < 16

I recommend use my lib. It`s already fixed:

here

cesards commented Oct 20, 2015

This snippet has a bug in devices with API < 16

I recommend use my lib. It`s already fixed:

here

@nv95

This comment has been minimized.

Show comment Hide comment
@nv95

nv95 Oct 23, 2015

Thanks! But it's will be better for using in xml with additional constructors:

    public TopCropImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setScaleType(ScaleType.MATRIX);
    }

    public TopCropImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setScaleType(ScaleType.MATRIX);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public TopCropImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        setScaleType(ScaleType.MATRIX);
    }

nv95 commented Oct 23, 2015

Thanks! But it's will be better for using in xml with additional constructors:

    public TopCropImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setScaleType(ScaleType.MATRIX);
    }

    public TopCropImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setScaleType(ScaleType.MATRIX);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public TopCropImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        setScaleType(ScaleType.MATRIX);
    }
@MrVilkaman

This comment has been minimized.

Show comment Hide comment
@MrVilkaman

MrVilkaman Feb 2, 2016

to left side add matrix.postTranslate(viewWidth - drawableWidth*scale,0); after matrix.setScale(scale, scale);

to left side add matrix.postTranslate(viewWidth - drawableWidth*scale,0); after matrix.setScale(scale, scale);

@naeimrezaeian

This comment has been minimized.

Show comment Hide comment
@naeimrezaeian

naeimrezaeian Apr 9, 2016

when i use this class compile show this error
android.view.InflateException: Binary XML file

when i use this class compile show this error
android.view.InflateException: Binary XML file

@jrh4016

This comment has been minimized.

Show comment Hide comment
@jrh4016

jrh4016 Apr 14, 2016

I'd love to get an explanation on how to use this in detail.

I've created a new file with this name and copied over the code. I then changed my ImageView to a TopCropImageView in XML, but I'm getting a litany of errors
Custom view TopCropImageView is not using the 2- or 3-argument View constructors; XML attributes will not work
java.lang.NullPointerException at line 35
Unable to start activity... android.view.InflateException: Binary XML file line #62: Binary XML file line #62: Error inflating class

jrh4016 commented Apr 14, 2016

I'd love to get an explanation on how to use this in detail.

I've created a new file with this name and copied over the code. I then changed my ImageView to a TopCropImageView in XML, but I'm getting a litany of errors
Custom view TopCropImageView is not using the 2- or 3-argument View constructors; XML attributes will not work
java.lang.NullPointerException at line 35
Unable to start activity... android.view.InflateException: Binary XML file line #62: Binary XML file line #62: Error inflating class

@Firsto

This comment has been minimized.

Show comment Hide comment
@Firsto

Firsto Apr 18, 2016

add this code

Firsto commented Apr 18, 2016

add this code

@barakhadar

This comment has been minimized.

Show comment Hide comment
@barakhadar

barakhadar Apr 19, 2016

First, great stuff! It works great! But, there's a but.. What I'm looking for is exactly the opposite...
How do I modify the code so that I'll have the same effect, but with the bottom of my image rather that it's top (as it works by default) ?

First, great stuff! It works great! But, there's a but.. What I'm looking for is exactly the opposite...
How do I modify the code so that I'll have the same effect, but with the bottom of my image rather that it's top (as it works by default) ?

@barakhadar

This comment has been minimized.

Show comment Hide comment
@barakhadar

barakhadar Apr 19, 2016

Never mind... Thanks to @MrVilkaman answer, I found the way.. Thanks dude!

So what you'll do to accomplish that, simply add at the bottom of the class, right after matrix.setScale(scale, scale);, this line : matrix.postTranslate( 0, viewHeight - drawableHeight * scale);.

Hope it will help someone else too..
Cheers!

Never mind... Thanks to @MrVilkaman answer, I found the way.. Thanks dude!

So what you'll do to accomplish that, simply add at the bottom of the class, right after matrix.setScale(scale, scale);, this line : matrix.postTranslate( 0, viewHeight - drawableHeight * scale);.

Hope it will help someone else too..
Cheers!

@arriolac

This comment has been minimized.

Show comment Hide comment
@arriolac

arriolac Jul 26, 2016

It's been a while since I've updated this class which explains why there's some issues/warnings caused by newer APIs. I'll be posting an update to this code soon.

Owner

arriolac commented Jul 26, 2016

It's been a while since I've updated this class which explains why there's some issues/warnings caused by newer APIs. I'll be posting an update to this code soon.

@arriolac

This comment has been minimized.

Show comment Hide comment
@arriolac

arriolac Jul 27, 2016

Updated gist to now work when inflated in XML and making sure that the drawable is not null before using it.

Owner

arriolac commented Jul 27, 2016

Updated gist to now work when inflated in XML and making sure that the drawable is not null before using it.

@seyoung-hyun

This comment has been minimized.

Show comment Hide comment
@seyoung-hyun

seyoung-hyun Feb 12, 2018

@arriolac
Thanks your code :)
Can I use your code in my commercial app?
Please let me know how I can use the code for commercial distribution.

@arriolac
Thanks your code :)
Can I use your code in my commercial app?
Please let me know how I can use the code for commercial distribution.

@klemenzarn

This comment has been minimized.

Show comment Hide comment
@klemenzarn

klemenzarn Apr 11, 2018

Thanks for this.

Thanks for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment