详解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...

ImageView的android:adjustViewBounds属性

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

android Mediaplayer各种属性和方法简单介绍

主要涉及类:MediaPlayer(1) 当一个MediaPlayer对象被创建或者调用reset()方法之后,它处于空闲状态,调用release()方法后处于结束状态#####1,一个MediaPl...

初学MediaPlayer,借鉴下别人的东西,希望共同学习进步。

初学MediaPlayer,借鉴下别人的东西,希望共同学习进步,希望下次能有自己的原创作品。

VideoView源码修改,实现按给定长宽播放视频

/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Ve...

Android GridView扩展仿微信微博发图动态添加删除图片

在平时的开发中,我们会看到不管是微信发朋友圈照片还是微博发布新鲜事,添加图片的时候都是选完后面还有个+号再去选择图片,这样的话比较方便用户去添加图片,有的右上角还有个-号方便用户去删除图片,而一般用户...

Imageview.setAdjustViewBounds用法

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

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

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

RecyclerView的使用(4)之下拉刷新和上拉加载

这篇介绍下如何为RecyclerView添加下拉刷新和上拉加载,过去在ListView当中添加下拉刷新和上拉加载是非常方便的利用addHeaderView和addFooterView,Recycler...

Android 设置ImageView宽度固定,其高度按比例缩放适应

今天和项目经理对喷了一下,他说在应用的列表数据中的图片应该宽度固定,高度按比例缩放自适应,我说,那岂不是很丑!直接让运营那边把图片处理成固定宽高比不就好了,省的我客户端麻烦了。 这家伙不同意,为毛呢,...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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