I'm coding android and I have a imageview. I want to set scaletype of this to topcrop. I could find centercrop in options, but it's not my request. How do I do?
Asked
Active
Viewed 1.8k times
4 Answers
32
Custom Android ImageView for top-crop scaling of the contained drawable.
import android.content.Context;
import android.graphics.Matrix;
import android.widget.ImageView;
/**
* ImageView to display top-crop scale of an image view.
*
* @author Chris Arriola
*/
public class TopCropImageView extends ImageView {
public TopCropImageView(Context context) {
super(context);
setScaleType(ScaleType.MATRIX);
}
@Override
protected boolean setFrame(int l, int t, int r, int b) {
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);
setImageMatrix(matrix);
return super.setFrame(l, t, r, b);
}
}

Jay
- 1,474
- 9
- 13
-
how to implement this. i asked a question regarding this http://stackoverflow.com/questions/32359213/trying-to-use-custom-imageview-topcrop-in-android-but-the-the-app-stops. – Santhosh Sep 02 '15 at 17:33
-
@Jay it works great. Im making matrix computations in onLayout() method, which gets called in on rotation also, where setFrame doesn't. – box Jul 29 '16 at 12:00
-
2I call super.setFrame(l, t, r, b); in the beginning or getWidth() will return 0 – JackWu Mar 07 '18 at 14:06
14
I just wanted a temporary solution without excess work . Try this
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:scrollY="-100dp"
android:id="@+id/poster"
/>
scrollY pulls your image up or down. Try it with different dp's and you 'll find the right size.

rahulxyz
- 437
- 4
- 12
-
8While this achieves the task at hand, it does not work for different screen resolutions or parent view sizes. Probably not recommended for production, as you will get unexpected results in the wild. :) – DoctorD Jun 10 '17 at 17:14
-
Yes, that's true i learned it the hard way. It behaves differently on various screens. – rahulxyz Jun 10 '17 at 19:03
-
I only needed to move the image slightly and this worked perfectly, thanks. – HB. Jul 06 '18 at 08:28
4
I don't believe you need a custom Image View for this. All you have to do is set the scaleType
to matrix
and set a custom matrix to the ImageView
.
1
Fixed version:
- setFrame calling asap
- not reusing Matrix -> it caused issue that when image realoaded too soon (with Picasso), the image was scaled too much
import android.content.Context
import android.graphics.Matrix
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView
class TopCropImageView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
) : AppCompatImageView(context, attrs, defStyleAttr) {
init {
scaleType = ScaleType.MATRIX
}
override fun setFrame(l: Int, t: Int, r: Int, b: Int): Boolean {
super.setFrame(l, t, r, b)
val matrix = Matrix()
val scale: Float
val viewWidth: Int = width - paddingLeft - paddingRight
val viewHeight: Int = height - paddingTop - paddingBottom
val drawableWidth: Int = drawable.intrinsicWidth
val drawableHeight: Int = drawable.intrinsicHeight
scale = if (drawableWidth * viewHeight > drawableHeight * viewWidth) {
viewHeight.toFloat() / drawableHeight.toFloat()
} else {
viewWidth.toFloat() / drawableWidth.toFloat()
}
matrix.setScale(scale, scale)
imageMatrix = matrix
return true
}
}

hrach
- 2,443
- 2
- 26
- 37