前言
本文主要讲解以Matrix
方式实现ImageView
对应的各种ScaleType
效果。通过代码实现,我们能更清晰的看到各种ScaleType
的区别,更深刻的理解各种ScaleType
的作用及其适用场景。
先放上效果图:
Demo1 | Demo2 | Demo3 |
---|---|---|
正文
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
- 对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
- 保持图片的宽高比,对图片进行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
- 保持图片的宽高比,对图片进行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
- 保持图片的宽高比,对图片进行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
- 图片居中显示在
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
- 保持图片的宽高比,等比例对图片进行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
- 如果图片宽度<=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
- 使用
Matrix
绘制图片。
GitHub
本文相关代码已上传GitHub,地址如下:
https://github.com/kongpf8848/AndroidWorld