0
点赞
收藏
分享

微信扫一扫

彻底搞懂ImageView的ScaleType,用Matrix实现各种ScaleType效果

科牛 2021-09-24 阅读 62
日记本

前言

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

先放上效果图:

Demo1 Demo2 Demo3

正文

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

  • 对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

举报

相关推荐

0 条评论