說(shuō)明一下環(huán)境
就是要設(shè)置一個(gè)imageview 的src屬性,這個(gè)圖片要保證不能被拉伸,同時(shí)還要適配不同屏幕,所以我們一一般的做法就是設(shè)置imageview的lw,是match_parent,lh是wrap_content
這個(gè)時(shí)候 就出現(xiàn)了如圖的效果
圖片是保持了包裹圖片原有的大小,但是imageview為什么還多出來(lái)了上下兩個(gè)部分?
這時(shí)候 聰明的大佬肯定就會(huì)說(shuō) sb,設(shè)置scaleType啊!
好的 大佬,我設(shè)置給你看(首先要知道,imageview默認(rèn)的scaleType是fitcenter,),那么這種情況, 我愚鈍只能設(shè)置成fitxy吧,如圖
好的 被拉伸了。
這個(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)致了上訴情況。