Android ImageView-ScaleType源码

来源:互联网 发布:mysql关闭3306端口 编辑:程序博客网 时间:2024/06/05 23:07

首先简单介绍下不同的ScaleType,其实看名字就知道,Scale(比例)Type(类型),这个对象用以调整图片的比例缩放类型。

不同的ScaleType影响的就是图片长与宽的不同缩放比例。matrix 用矩阵来绘制(从左上角起始的矩阵区域)

 
fitXY  把图片不按比例扩大/缩小到View的大小显示(确保图片会完整显示,并充满View)
 
fitStart  把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置(图片会完整显示)
 
fitCenter  把图片按比例扩大/缩小到View的宽度,居中显示(图片会完整显示)
 
fitEnd   把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置(图片会完整显示)

center  按图片的原来size居中显示,当图片宽超过View的宽,则截取图片的居中部分显示,当图片宽小于View的宽,则图片居中显示
 
centerCrop  按比例扩大/缩小图片的size居中显示,使得图片的高等于View的高,使得图片宽等于或大于View的宽
 
centerInside  将图片的内容完整居中显示,使得图片按比例缩小或原来的大小(图片比View小时)使得图片宽等于或小于View的宽 (图片会完整显示)

  public void setScaleType(ScaleType scaleType) {        if (scaleType == null) {            throw new NullPointerException();        }        if (mScaleType != scaleType) {            mScaleType = scaleType;            setWillNotCacheDrawing(mScaleType == ScaleType.CENTER);                        requestLayout();            invalidate();        }    }
当设置的 scaleType    和原来 mScaleType  = ScaleType.FIT_CENTER  不一样就 则设置缩放类型为scaleType  进行刷新操作 ;
requestLayout() 该view本身调用这个方法要求parent view重新调用他的onMeasure onLayout来对重新设置自己位置。
特别的当view的layoutparameter发生改变,并且它的值还没能应用到view上,这时候适合调用这个方法。
invalidate:View本身调用迫使view重画。
setWillNotCacheDrawing(mScaleType == ScaleType.CENTER); 设置当参数等于true 不能画缓存,否则可以画缓存
    /**     * When a View's drawing cache is enabled, drawing is redirected to an     * offscreen bitmap. Some views, like an ImageView, must be able to     * bypass this mechanism if they already draw a single bitmap, to avoid     * unnecessary usage of the memory.     *     * @param willNotCacheDrawing true if this view does not cache its     *        drawing, false otherwise     */    public void setWillNotCacheDrawing(boolean willNotCacheDrawing) {        setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING);    }

当View绘画的时候启用缓存,绘画会重定向到一个

画面以外的位图。例如以一些View,比如一个ImageView,如果他们已经画好一个位图 则可以

忽略这种缓存机制,以避免不必要的内存开销。

    /**     * Returns whether or not this View can cache its drawing or not.     *     * @return true if this view does not cache its drawing, false otherwise     */    @ViewDebug.ExportedProperty(category = "drawing")    public boolean willNotCacheDrawing() {        return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING;    }
willNotCacheDrawing()方法放回false 则可以画缓存。


看 ImageView 源码  configureBounds()方法 ,

configureBounds用以处理Matrix和ScaleType的关系

private void configureBounds() {
        if (mDrawable == null || !mHaveFrame) {
            return;
        }


        int dwidth = mDrawableWidth;
        int dheight = mDrawableHeight;


        int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
        int vheight = getHeight() - mPaddingTop - mPaddingBottom;


        boolean fits = (dwidth < 0 || vwidth == dwidth) &&
                       (dheight < 0 || vheight == dheight);


        if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
            /* If the drawable has no intrinsic size, or we're told to
                scaletofit, then we just fill our entire view.
            */
            mDrawable.setBounds(0, 0, vwidth, vheight);
            mDrawMatrix = null;
        } else {
            // We need to do the scaling ourself, so have the drawable
            // use its native size.
            mDrawable.setBounds(0, 0, dwidth, dheight);


            if (ScaleType.MATRIX == mScaleType) {
                // Use the specified matrix as-is.
                if (mMatrix.isIdentity()) {
                    mDrawMatrix = null;
                } else {
                    mDrawMatrix = mMatrix;
                }
            } else if (fits) {
                // The bitmap fits exactly, no transform needed.
                mDrawMatrix = null;
            } else if (ScaleType.CENTER == mScaleType) {
                // Center bitmap in view, no scaling.
                mDrawMatrix = mMatrix;
                mDrawMatrix.setTranslate((int) ((vwidth - dwidth) * 0.5f + 0.5f),
                                         (int) ((vheight - dheight) * 0.5f + 0.5f));
            } else if (ScaleType.CENTER_CROP == mScaleType) {
                mDrawMatrix = mMatrix;


                float scale;
                float dx = 0, dy = 0;


                if (dwidth * vheight > vwidth * dheight) {
                    scale = (float) vheight / (float) dheight; 
                    dx = (vwidth - dwidth * scale) * 0.5f;
                } else {
                    scale = (float) vwidth / (float) dwidth;
                    dy = (vheight - dheight * scale) * 0.5f;
                }


                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
            } else if (ScaleType.CENTER_INSIDE == mScaleType) {
                mDrawMatrix = mMatrix;
                float scale;
                float dx;
                float dy;
                
                if (dwidth <= vwidth && dheight <= vheight) {
                    scale = 1.0f;
                } else {
                    scale = Math.min((float) vwidth / (float) dwidth,
                            (float) vheight / (float) dheight);
                }
                
                dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f);
                dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f);


                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate(dx, dy);
            } else {
                // Generate the required transform.
                mTempSrc.set(0, 0, dwidth, dheight);
                mTempDst.set(0, 0, vwidth, vheight);
                
                mDrawMatrix = mMatrix;
                mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
            }
        }
    }


dwidth  dheight是drawable 的宽高
vwidth  vheight是控件的实际宽高
boolean fits=? 如果图片大小未知或者 图片大小和控件相等 则返回true
分段分析:
if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {            /* If the drawable has no intrinsic size, or we're told to                scaletofit, then we just fill our entire view.            */            mDrawable.setBounds(0, 0, vwidth, vheight);            mDrawMatrix = null;        }      
如果drawable 大小未知,或者我们指定了 scaleType.FIT_XY类型 则drawable边界设置为 长宽是 控件长度和宽度。
setBounds方法用以设置Drawable绘制区域的大小,是一个矩形对象。在ImageView的onDraw方法中,最终会将Drawable表示的图片绘制到该区域上。 mDrawMatrix=null, 不需要用到matrix 了 因为已经填充好整个控件
else {            // We need to do the scaling ourself, so have the drawable            // use its native size.            mDrawable.setBounds(0, 0, dwidth, dheight);            if (ScaleType.MATRIX == mScaleType) {                // Use the specified matrix as-is.                if (mMatrix.isIdentity()) {                    mDrawMatrix = null;                } else {                    mDrawMatrix = mMatrix;                }            }
如果 图片大小已知  设置Bounds 为图片的实际宽高, if设置的类型是 ScaleType.MARIX,
用指定的matrix设置给canvas 在onDraw里的canvas.concat方法
  if (mDrawMatrix != null) {                canvas.concat(mDrawMatrix);            }

else if (fits) {                // The bitmap fits exactly, no transform needed.                mDrawMatrix = null;            } else if (ScaleType.CENTER == mScaleType) {                // Center bitmap in view, no scaling.                mDrawMatrix = mMatrix;                mDrawMatrix.setTranslate((int) ((vwidth - dwidth) * 0.5f + 0.5f),                                         (int) ((vheight - dheight) * 0.5f + 0.5f));            }
如果设置的scaleType是 scaleType.FIT_XY 则 mDrawMatrix=null 不要缩放操作
如果scaleType是CENTER 则将drawable向右下移动 居中显示。

 else if (ScaleType.CENTER_CROP == mScaleType) {                mDrawMatrix = mMatrix;                float scale;                float dx = 0, dy = 0;                if (dwidth * vheight > vwidth * dheight) {                    scale = (float) vheight / (float) dheight;                     dx = (vwidth - dwidth * scale) * 0.5f;.
                } else {                    scale = (float) vwidth / (float) dwidth;                    dy = (vheight - dheight * scale) * 0.5f;                }                mDrawMatrix.setScale(scale, scale);                mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));            }
如果类型是CENTER_CROP    dwidth * vheight > vwidth * dheight  转化成    dwidth/vwidth>dheight/vheight,即判断到底是图片的宽度比较接近控件宽度还是图片高度比较控件高度,最终会取相差较大的项,将其放大至控件对应的值。而另外一项将超出控件大小。之后,对其进行位移,使超出控件大小的一项居中显示。注:当图片大于控件时,是将超出更少的项进行缩放。CROP的目的在于对图片宽高进行变换,使其中一项和控件的值相等,另外一项大于控件的值。
else if (ScaleType.CENTER_INSIDE == mScaleType) {                mDrawMatrix = mMatrix;                float scale;                float dx;                float dy;                                if (dwidth <= vwidth && dheight <= vheight) {                    scale = 1.0f;                } else {                    scale = Math.min((float) vwidth / (float) dwidth,                            (float) vheight / (float) dheight);                }                                dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f);                dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f);                mDrawMatrix.setScale(scale, scale);                mDrawMatrix.postTranslate(dx, dy);            }

7.当为CENTER_INSIDE时,若图片高宽均小于控件高宽,则不进行缩放只进行偏移,偏移方式跟其他情况相同。否则,将根据图片和控件的宽高比例差距更大的一项进行缩放,缩放的结果就是其中一项和控件相同,另外一项小于控件值。这个刚好和CENTER_CROP相反。

 

else {                // Generate the required transform.                mTempSrc.set(0, 0, dwidth, dheight);                mTempDst.set(0, 0, vwidth, vheight);                                mDrawMatrix = mMatrix;                mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));            }

 

8.最后三种FIT_CENTER、FIT_START、FIT_END都是调用setRectToRect获取缩放偏移矩阵。setRectTorect返回一个Matrix,该Matrix表示从矩形mTempSrc到mTemDst的变换矩阵,根据第三个参数Matrix.ScaleToFit来确定缩放选项。

Matrix.ScaleToFit定义了四种选项:

CENTER: 保持坐标变换前矩形的长宽比,并最大限度的填充变换后的矩形。至少有一边和目标矩形重叠。
END:保持坐标变换前矩形的长宽比,并最大限度的填充变换后的矩形。至少有一边和目标矩形重叠。END提供右下对齐。
FILL: 可能会变换矩形的长宽比,保证变换和目标矩阵长宽一致。
START:保持坐标变换前矩形的长宽比,并最大限度的填充变换后的矩形。至少有一边和目标矩形重叠。START提供左上对齐。

ScaleType的FIT_CENTER、FIT_START、FIT_END分别对应于这里的CENTER、END、START。

总结下就一句话:ScaleType本质上是影响了ImageView中的mDrawMatrix对象,该对象用以在绘制时对Drawable对象进行矩阵转换。






 








0 0
原创粉丝点击