详解android:scaleType和android:adjustViewBounds属性

原创 2015年11月18日 23:21:15

一、Android:scaleType

android的scaleType属于View的视图层,在onDraw时通过给canvas添加不同的Maxtrix来达到不同的展现效果。
下面结合源码分析的每一种类型的含义:

   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.
            */
            // 对于 fixXY模式,直接图片的宽度伸缩成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) {// 当图片的宽度与View的宽度一样时,优先处理
                // The bitmap fits exactly, no transform needed.
                mDrawMatrix = null;
            } else if (ScaleType.CENTER == mScaleType) {
                // 对于center模式,只是将图片平衡到View的中心位置
                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;

                // 对于centerCrop模式,其会将图片等比伸缩到一条边与View重合,另一条与View重合或超过
                // 然后,平移至view的中心
                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;
                // 对于centerInside模式,其是将图片的边界完全等比伸缩到View的里面,可能出现边界重合
                // 然后平移到View的中心位置
                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 {
                // 下面是fitStart/fitCenter/fitEnd模式,它是将图片等比伸缩到View里面,类似于
                //centerInside,不同的是其可以放置于开始、中间和结束三个不同的位置
                mTempSrc.set(0, 0, dwidth, dheight);
                mTempDst.set(0, 0, vwidth, vheight);

                mDrawMatrix = mMatrix;
                mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
            }
        }
    }
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

           .......
           // 将先前调整过的Matrix添加到canvas里面,并与之前的Maxtric连接起来
            if (mDrawMatrix != null) {
                canvas.concat(mDrawMatrix);
            }
            mDrawable.draw(canvas);
            canvas.restoreToCount(saveCount);
        }
    }

二、Android:adjustViewBounds

Android的adjustViewBounds属于View的属性层,在onMeasure时通过控制View的宽高比来影响View的大小。而宽度比是根据加载的图片的宽高算的。也就是说可以通过设置adjustViewBounds为true,来调整View的宽度比等于加载图片的宽度比。这往往会结合scaleType=centerCrop用于等比例显示图片。
调整View宽高比的源码如下:

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        resolveUri();
        int w;
        int h;
        float desiredAspect = 0.0f;
        boolean resizeWidth = false;
        boolean resizeHeight = false;

        final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);

        if (mDrawable == null) {
            // If no drawable, its intrinsic size is 0.
            mDrawableWidth = -1;
            mDrawableHeight = -1;
            w = h = 0;
        } else {
            w = mDrawableWidth;
            h = mDrawableHeight;
            if (w <= 0) w = 1;
            if (h <= 0) h = 1;

            // We are supposed to adjust view bounds to match the aspect
            // ratio of our drawable. See if that is possible.
            if (mAdjustViewBounds) {

                // 当你设置的宽(或高)值为wrap_content时,会触发相应的宽(或高)的长度的调整
                resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
                resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;

                // 调整时用的宽高比例就是图片资源的宽高比
                desiredAspect = (float) w / (float) h;
            }
        }

        if (resizeWidth || resizeHeight) {
            // Get the max possible width given our constraints
            widthSize = resolveAdjustedSize(w + pleft + pright, mMaxWidth, widthMeasureSpec);

            // Get the max possible height given our constraints
            heightSize = resolveAdjustedSize(h + ptop + pbottom, mMaxHeight, heightMeasureSpec);

            if (desiredAspect != 0.0f) {
                // See what our actual aspect ratio is
                float actualAspect = (float)(widthSize - pleft - pright) /
                                        (heightSize - ptop - pbottom);

                if (Math.abs(actualAspect - desiredAspect) > 0.0000001) {
                    boolean done = false;

                    // 等比例调整宽度
                    if (resizeWidth) {
                        int newWidth = (int)(desiredAspect * (heightSize - ptop - pbottom)) + pleft + pright;
                        if (newWidth <= widthSize) {
                            widthSize = newWidth;
                            done = true;
                        } 
                    }

                    // 等比例调整高度
                    if (!done && resizeHeight) {
                        int newHeight = (int)((widthSize - pleft - pright) / desiredAspect) +
                                ptop + pbottom;
                        if (newHeight <= heightSize) {
                            heightSize = newHeight;
                        }
                    }
                }
            }
        } else {
        }

        setMeasuredDimension(widthSize, heightSize);
    }

ImageView中android:adjustViewBounds属性

public voidsetAdjustViewBounds(boolean adjustViewBounds) Since: API Level 1 Set this to true...
  • xiahao86
  • xiahao86
  • 2013年11月20日 13:52
  • 23071

Android ImageView scaleType+adjustViewBounds两个属性详解 保证图片不变形

转自:http://www.2cto.com/kf/201411/348601.html 记得当初学习ImageView 的时候,觉得很简单,很基础。 直到两年后我才开始使用adjustViewBo...

ImageView的android:adjustViewBounds属性

取值为true时: Adjust the ImageView's bounds to preserve the aspect ration of its drawable. 调整ImageView的界...

android ImageView android:adjustViewBounds属性的作用

android:adjustViewBounds  是否保持宽高比。需要与maxWidth、MaxHeight一起使用,否则单独使用没有效果。  android:cropToPadding  ...

Imageview.setAdjustViewBounds用法

public void setAdjustViewBounds (boolean adjustViewBounds) 当你需要在 ImageView调整边框时保持可绘制对象的比例时,将该值设为真。 ...
  • DQ1005
  • DQ1005
  • 2015年08月25日 15:25
  • 2658

ImageView.adjustViewBounds属性

取值为true时: Adjust the ImageView's bounds to preserve the aspect ration of its drawable. 调整ImageView...

imageView高度与显示问题:scaleType属性,adjustViewBounds属性

imageView高度和宽度问题主要包括scaleType属性和adjustViewBounds属性,并且介绍它们的属性与使用问题。...

ImageView的android:adjustViewBounds属性

取值为true时: Adjust the ImageView's bounds to preserve the aspect ration of its drawable. 调整ImageView...
  • onceing
  • onceing
  • 2016年05月31日 17:26
  • 445

android:visibility和android:scaleType 属性

1.android:visibility="gone" 其有三个属性:visible显示;invisible显示黑背景条;gone不显示 2.android:scaleType属性 ...
  • Buaaroid
  • Buaaroid
  • 2014年05月21日 12:58
  • 11513

Android ImageView属性adjustViewBounds和ScaleType的介绍

在研究Android项目的时候看到了ImageView的adjustViewBounds和ScaleType这两个属性,想知道具体怎么使用,所以查阅了相关资料和官方文档。...
  • fanKarl
  • fanKarl
  • 2016年07月28日 16:05
  • 240
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:详解android:scaleType和android:adjustViewBounds属性
举报原因:
原因补充:

(最多只允许输入30个字)