adjustViewBounds說(shuō)明

說(shuō)明一下環(huán)境
就是要設(shè)置一個(gè)imageview 的src屬性,這個(gè)圖片要保證不能被拉伸,同時(shí)還要適配不同屏幕,所以我們一一般的做法就是設(shè)置imageview的lw,是match_parent,lh是wrap_content

這個(gè)時(shí)候 就出現(xiàn)了如圖的效果


Snip20170721_1.png

圖片是保持了包裹圖片原有的大小,但是imageview為什么還多出來(lái)了上下兩個(gè)部分?
這時(shí)候 聰明的大佬肯定就會(huì)說(shuō) sb,設(shè)置scaleType啊!
好的 大佬,我設(shè)置給你看(首先要知道,imageview默認(rèn)的scaleType是fitcenter,),那么這種情況, 我愚鈍只能設(shè)置成fitxy吧,如圖

Snip20170721_2.png

好的 被拉伸了。
這個(gè)時(shí)候 我就像大佬那樣,設(shè)置完 也不管拉伸與否,就提交上去了,后來(lái)我的老大jack就看出來(lái)了,給我指導(dǎo)一番,說(shuō)出了imageview的神屬性,adjustViewBounds 臥槽,真的一設(shè)置,就成了,而且 還不用設(shè)置了scaleType,真屌。

然后我就去谷歌這個(gè)屬性,看博客,有人說(shuō)的是設(shè)置了adjustViewBounds,還要必須設(shè)置maxWidth,maxHeight這兩個(gè)屬性,但是下面就是官網(wǎng)和源碼上的setxxx這個(gè)屬性的方法,看了注釋的意思也很明確就是就是讓iamageview符合內(nèi)部圖片的大小,但是網(wǎng)上別的文章就說(shuō) 設(shè)置了adjustViewBounds,還要必須設(shè)置maxWidth,maxHeight這兩個(gè)屬性,跟這個(gè)不同,還是去看一下源碼是怎么做到吧.

android:adjustViewBounds
Set this to true if you want the ImageView to adjust its bounds to preserve the aspect ratio of its drawable.
May be a boolean value, such as "true
" or "false
".

**Related methods:**
[setAdjustViewBounds(boolean)](https://developer.android.com/reference/android/widget/ImageView.html#setAdjustViewBounds(boolean))


/**
     * Set this to true if you want the ImageView to adjust its bounds
     * to preserve the aspect ratio of its drawable.
     *
     * <p><strong>Note:</strong> If the application targets API level 17 or lower,
     * adjustViewBounds will allow the drawable to shrink the view bounds, but not grow
     * to fill available measured space in all cases. This is for compatibility with
     * legacy {@link android.view.View.MeasureSpec MeasureSpec} and
     * {@link android.widget.RelativeLayout RelativeLayout} behavior.</p>
     *
     * @param adjustViewBounds Whether to adjust the bounds of this view
     * to preserve the original aspect ratio of the drawable.
     *
     * @see #getAdjustViewBounds()
     *
     * @attr ref android.R.styleable#ImageView_adjustViewBounds
     */
    @android.view.RemotableViewMethod
    public void setAdjustViewBounds(boolean adjustViewBounds) {
        mAdjustViewBounds = adjustViewBounds;
        if (adjustViewBounds) {
            setScaleType(ScaleType.FIT_CENTER);
        }
    }

有人說(shuō)會(huì)不會(huì)是背景顏色原因(并不是,我只是為了突出效果顯示,其實(shí)你可以試試,把背景去掉)
那就去看看源碼吧,理清一下思路
設(shè)置了adjustViewBounds那么imageview就會(huì)變得很聽(tīng)話,不設(shè)置,即使設(shè)置了scaleType還是沒(méi)卵用,那么adjustViewBounds肯定有關(guān)鍵的作用,所以去imageview的源碼里看看,
那就全局搜索adjustViewBounds
首先看到的是mAdjustViewBounds默認(rèn)是false沒(méi)有開(kāi)啟,
然后是set,get方法
然后是在onMeasure中用到了

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        resolveUri(); // 驗(yàn)證drawable的uri
        int w;
        int h;

        // Desired aspect ratio of the view's contents (not including padding)
        float desiredAspect = 0.0f;

        // We are allowed to change the view's width
        boolean resizeWidth = false;

        // We are allowed to change the view's height
        boolean resizeHeight = false;
//就正常自定義view那些東西
        final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);

        if (mDrawable == null) {//drawable為空 就都是0了
            // 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;
//不為空,那么就進(jìn)行賦值上drawable的大小
            // We are supposed to adjust view bounds to match the aspect
            // ratio of our drawable. See if that is possible.
//設(shè)置了adjustViewBounds,就會(huì)調(diào)整比例,將view的比例設(shè)置成
//drawable的比例,所以能夠完美展示。同時(shí)注意resizeWidth,只有當(dāng)view當(dāng)測(cè)量模式不是Exactly,就是(match_parent,和精準(zhǔn)當(dāng)XXdp)
            if (mAdjustViewBounds) {
                resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
                resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;

                desiredAspect = (float) w / (float) h;
            }
        }

        final int pleft = mPaddingLeft;
        final int pright = mPaddingRight;
        final int ptop = mPaddingTop;
        final int pbottom = mPaddingBottom;

        int widthSize;
        int heightSize;
//如果是精準(zhǔn)當(dāng)size,那么就得重新測(cè)量了,同時(shí)還需要設(shè)置adjustViewbounds屬性才行,因?yàn)橹挥性O(shè)置了adjustViewBounds屬性了才能對(duì)reseiz這兩個(gè)值進(jìn)行賦值,別的地方?jīng)]有賦值
        if (resizeWidth || resizeHeight) {

            /* If we get here, it means we want to resize to match the
                drawables aspect ratio, and we have the freedom to change at
                least one dimension.
            */

            // 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);
//如果設(shè)置了adjustViewBounds,然后根據(jù)比例對(duì)需要對(duì)寬高進(jìn)行縮放,是等比例縮放。
            if (desiredAspect != 0.0f) {
                // See what our actual aspect ratio is
                final float actualAspect = (float)(widthSize - pleft - pright) /
                                        (heightSize - ptop - pbottom);

                if (Math.abs(actualAspect - desiredAspect) > 0.0000001) {

                    boolean done = false;

                    // Try adjusting width to be proportional to height
                    if (resizeWidth) {
                        int newWidth = (int)(desiredAspect * (heightSize - ptop - pbottom)) +
                                pleft + pright;

                        // Allow the width to outgrow its original estimate if height is fixed.
                        if (!resizeHeight && !sCompatAdjustViewBounds) {
                            widthSize = resolveAdjustedSize(newWidth, mMaxWidth, widthMeasureSpec);
                        }

                        if (newWidth <= widthSize) {
                            widthSize = newWidth;
                            done = true;
                        }
                    }

                    // Try adjusting height to be proportional to width
                    if (!done && resizeHeight) {
                        int newHeight = (int)((widthSize - pleft - pright) / desiredAspect) +
                                ptop + pbottom;

                        // Allow the height to outgrow its original estimate if width is fixed.
                        if (!resizeWidth && !sCompatAdjustViewBounds) {
                            heightSize = resolveAdjustedSize(newHeight, mMaxHeight,
                                    heightMeasureSpec);
                        }

                        if (newHeight <= heightSize) {
                            heightSize = newHeight;
                        }
                    }
                }
            }
        } else {
        //如果沒(méi)有設(shè)置,那么久根據(jù)imageview的drawable的背景圖片的大小作為imageview的最小尺寸
            /* We are either don't want to preserve the drawables aspect ratio,
               or we are not allowed to change view dimensions. Just measure in
               the normal way.
            */
            w += pleft + pright;
            h += ptop + pbottom;

            w = Math.max(w, getSuggestedMinimumWidth());
            h = Math.max(h, getSuggestedMinimumHeight());

            widthSize = resolveSizeAndState(w, widthMeasureSpec, 0);
            heightSize = resolveSizeAndState(h, heightMeasureSpec, 0);
        }

        setMeasuredDimension(widthSize, heightSize);
    }

總結(jié)

其實(shí)adjutViewBounds 的作用就是當(dāng)Imageivew的寬或者設(shè)置成了At_Most模式后,會(huì)讓imageview的大小等比縮放變成了drawable的大小.

那么為什么imageview設(shè)置成wrap_content,會(huì)多出來(lái)寬的呢?去看源碼知道了,imageview的width,height是mDrawable的width,height,那么這個(gè)drawable的賦值是d.getIntrinsicHeight();,和d.getIntrinsicWidth();這個(gè)得來(lái)的,繼續(xù)追,發(fā)現(xiàn)這個(gè)是bitmapdrawable,然后看源碼


private void computeBitmapSize() {
        final Bitmap bitmap = mBitmapState.mBitmap;
        if (bitmap != null) {
            mBitmapWidth = bitmap.getScaledWidth(mTargetDensity);
            mBitmapHeight = bitmap.getScaledHeight(mTargetDensity);
        } else {
            mBitmapWidth = mBitmapHeight = -1;
        }
    }

這是賦值,他會(huì)根據(jù)mTargetDensity(屏幕的比例)這個(gè)屬性對(duì)bitmap的寬高進(jìn)行縮放,所以導(dǎo)致了上訴情況。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 最近在研究圖片加載庫(kù),趁機(jī)找時(shí)間學(xué)習(xí)下ImageView的源碼,探究下它內(nèi)部機(jī)制,同時(shí)學(xué)習(xí)下View的封裝思想。 ...
    guobin_xu閱讀 5,346評(píng)論 0 13
  • 一、正確合理使用ImageView 的src 和background src :為ImageView 原圖內(nèi)容,存...
    freddyyao閱讀 10,214評(píng)論 5 7
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,242評(píng)論 25 708
  • 白百何出軌事件持續(xù)發(fā)酵了三天,素有娛樂(lè)圈‘紀(jì)檢委’之稱(chēng)的卓偉連續(xù)兩天用“一指禪和摸臀殺”吸引了全民眼球,人人津津樂(lè)...
    言一是閱讀 604評(píng)論 0 0
  • 作者:玖鏡 序章 世界是灰白的,在我眼中或許已沒(méi)有能讓我看出彩色的東西。 破碎...消散....泯滅......
    玖鏡閱讀 336評(píng)論 1 1