美文网首页
彻底搞懂ImageView的ScaleType,用Matrix实

彻底搞懂ImageView的ScaleType,用Matrix实

作者: 孔鹏飞 | 来源:发表于2021-05-13 16:09 被阅读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.

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

    相关文章

      网友评论

          本文标题:彻底搞懂ImageView的ScaleType,用Matrix实

          本文链接:https://www.haomeiwen.com/subject/mkbadltx.html