彻底搞懂ImageView的ScaleType,用Matrix实
前言
本文主要讲解以Matrix
方式实现ImageView
对应的各种ScaleType
效果。通过代码实现,我们能更清晰的看到各种ScaleType
的区别,更深刻的理解各种ScaleType
的作用及其适用场景。
先放上效果图:
Demo1 | Demo2 | Demo3 |
---|---|---|
1.png | 2.png | 3.png |
正文
ScaleType
是用来控制图像如何调整大小或移动以匹配ImageView
I的大小,从ImageView
源码中可以得知ImageView
默认的ScaleType
为FIT_CENTER
。
//ImageView.java
private static final ScaleType[] sScaleTypeArray = {
ScaleType.MATRIX,
ScaleType.FIT_XY,
ScaleType.FIT_START,
ScaleType.FIT_CENTER,
ScaleType.FIT_END,
ScaleType.CENTER,
ScaleType.CENTER_CROP,
ScaleType.CENTER_INSIDE
};
private void initImageView() {
mMatrix = new Matrix();
mScaleType = ScaleType.FIT_CENTER;
if (!sCompatDone) {
final int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
sCompatAdjustViewBounds = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1;
sCompatUseCorrectStreamDensity = targetSdkVersion > Build.VERSION_CODES.M;
sCompatDrawableVisibilityDispatch = targetSdkVersion < Build.VERSION_CODES.N;
sCompatDone = true;
}
}
那么问题来了,每一种ScaleType
对应的实现是什么呢?通过查看ImageView
源码,发现其内部主要是通过Matrix
(3*3的矩阵)实现的。
ScaleType.FIT_XY
Scale in X and Y independently, so that src matches dst exactly. This may change the aspect ratio of the src.
- 对X和Y方向独立缩放,直到图片铺满
ImageView
。这种方式可能会改变图片原本的宽高比,导致图片拉伸变形。
fun ImageView.fitXY(){
if(drawable==null){
return
}
val dwidth=drawable.intrinsicWidth
val dheight=drawable.intrinsicHeight
val widthPercentage = width.toFloat() / dwidth.toFloat()
val heightPercentage = height.toFloat() / dheight.toFloat()
val matrix = Matrix()
matrix.setScale(widthPercentage, heightPercentage)
scaleType=ImageView.ScaleType.MATRIX
imageMatrix=matrix
}
ScaleType.FIT_START
Compute a scale that will maintain the original src aspect ratio, but will also ensure that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. START aligns the result to the left and top edges of dst.
- 保持图片的宽高比,对图片进行X和Y方向缩放,直到一个方向铺满
ImageView
。 - 缩放后的图片与
ImageView
左上角对齐进行显示。
fun ImageView.fitStart(){
if(drawable==null){
return
}
val dwidth=drawable.intrinsicWidth
val dheight=drawable.intrinsicHeight
val widthPercentage = width.toFloat() / dwidth.toFloat()
val heightPercentage = height.toFloat() / dheight.toFloat()
val minPercentage = Math.min(widthPercentage, heightPercentage)
val matrix = Matrix()
matrix.setScale(minPercentage, minPercentage)
scaleType=ImageView.ScaleType.MATRIX
imageMatrix=matrix
}
ScaleType.FIT_CENTER
Compute a scale that will maintain the original src aspect ratio, but will also ensure that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. The result is centered inside dst.
- 保持图片的宽高比,对图片进行X和Y方向缩放,直到一个方向铺满
ImageView
。 - 缩放后的图片居中显示在
ImageView
中。
fun ImageView.fitCenter(){
if(drawable==null){
return
}
val dwidth=drawable.intrinsicWidth
val dheight=drawable.intrinsicHeight
val widthPercentage = width.toFloat() / dwidth.toFloat()
val heightPercentage = height.toFloat() / dheight.toFloat()
val minPercentage = Math.min(widthPercentage, heightPercentage)
val targetWidth = (minPercentage * dwidth).roundToInt()
val targetHeight = (minPercentage * dheight).roundToInt()
val matrix = Matrix()
matrix.setScale(minPercentage, minPercentage)
matrix.postTranslate((width-targetWidth)*0.5f, (height-targetHeight)*0.5f)
scaleType=ImageView.ScaleType.MATRIX
imageMatrix=matrix
}
ScaleType.FIT_END
Compute a scale that will maintain the original src aspect ratio, but will also ensure that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. END aligns the result to the right and bottom edges of dst.
- 保持图片的宽高比,对图片进行X和Y方向缩放,直到一个方向铺满
ImageView
。 - 缩放后的图片与
ImageView
右下角对齐进行显示。
fun ImageView.fitEnd(){
if(drawable==null){
return
}
val dwidth=drawable.intrinsicWidth
val dheight=drawable.intrinsicHeight
val widthPercentage = width.toFloat() / dwidth.toFloat()
val heightPercentage = height.toFloat() / dheight.toFloat()
val minPercentage = Math.min(widthPercentage, heightPercentage)
val matrix = Matrix()
val targetWidth = (minPercentage * dwidth).roundToInt()
val targetHeight = (minPercentage * dheight).roundToInt()
matrix.setScale(minPercentage, minPercentage)
matrix.postTranslate((width-targetWidth).toFloat(), (height-targetHeight).toFloat())
scaleType=ImageView.ScaleType.MATRIX
imageMatrix=matrix
}
ScaleType.CENTER
Center the image in the view, but perform no scaling.
- 图片居中显示在
ImageView
中,不对图片进行缩放。
fun ImageView.center(){
if(drawable==null){
return
}
val dwidth=drawable.intrinsicWidth
val dheight=drawable.intrinsicHeight
val matrix = Matrix()
matrix.setTranslate((width - dwidth) * 0.5f, (height - dheight) * 0.5f)
scaleType=ImageView.ScaleType.MATRIX
imageMatrix=matrix
}
ScaleType.CENTER_CROP
Scale the image uniformly (maintain the image's aspect ratio) so both dimensions (width and height) of the image will be equal to or larger than the corresponding dimension of the view (minus padding). The image is then centered in the view.
- 保持图片的宽高比,等比例对图片进行X和Y方向缩放,直到每个方向都大于等于
ImageView
对应的尺寸。 - 缩放后的图片居中显示在
ImageView
中,超出部分做裁剪处理。
fun ImageView.centerCrop(){
if(drawable==null){
return
}
val dwidth=drawable.intrinsicWidth
val dheight=drawable.intrinsicHeight
val scale: Float
val dx:Float
val dy:Float
if (dwidth * height > width * dheight) {
scale = height.toFloat() / dheight.toFloat()
dx = (width - dwidth * scale) * 0.5f
dy=0f
} else {
scale = width.toFloat() / dwidth.toFloat()
dx=0f
dy = (height - dheight * scale) * 0.5f
}
val matrix = Matrix()
matrix.setScale(scale, scale)
matrix.postTranslate(dx + 0.5f, dy+0.5f)
scaleType=ImageView.ScaleType.MATRIX
imageMatrix=matrix
}
ScaleType.CENTER_INSIDE
Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or less than the corresponding dimension of the view (minus padding). The image is then centered in the view.
- 如果图片宽度<=ImageView宽度
&&
图片高度<=ImageView高度,不执行缩放,居中显示在ImageView
中。 - 其余情况按
ScaleType.FIT_CENTER
处理。
fun ImageView.centerInside(){
if(drawable==null){
return
}
val dwidth=drawable.intrinsicWidth
val dheight=drawable.intrinsicHeight
if(dwidth<=width && dheight<=height){
val matrix = Matrix()
matrix.setTranslate((width-dwidth)*0.5f, (height-dwidth)*0.5f)
scaleType=ImageView.ScaleType.MATRIX
imageMatrix=matrix
}
else{
fitCenter()
}
}
ScaleType.MATRIX
Scale using the image matrix when drawing
- 使用
Matrix
绘制图片。
GitHub
本文相关代码已上传GitHub,地址如下:
https://github.com/kongpf8848/AndroidWorld