彻底搞懂ImageView的ScaleType,用Matrix实

2021-05-13  本文已影响0人  孔鹏飞

前言

本文主要讲解以Matrix方式实现ImageView对应的各种ScaleType效果。通过代码实现,我们能更清晰的看到各种ScaleType的区别,更深刻的理解各种ScaleType的作用及其适用场景。

先放上效果图:

Demo1 Demo2 Demo3
1.png 2.png 3.png

正文

ScaleType是用来控制图像如何调整大小或移动以匹配ImageViewI的大小,从ImageView源码中可以得知ImageView默认的ScaleTypeFIT_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.

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.

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.

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.

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.

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.

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.

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

GitHub

本文相关代码已上传GitHub,地址如下:
https://github.com/kongpf8848/AndroidWorld

上一篇下一篇

猜你喜欢

热点阅读