说明一下环境
就是要设置一个imageview 的src属性,这个图片要保证不能被拉伸,同时还要适配不同屏幕,所以我们一一般的做法就是设置imageview的lw,是match_parent,lh是wrap_content
这个时候 就出现了如图的效果
图片是保持了包裹图片原有的大小,但是imageview为什么还多出来了上下两个部分?
这时候 聪明的大佬肯定就会说 sb,设置scaleType啊!
好的 大佬,我设置给你看(首先要知道,imageview默认的scaleType是fitcenter,),那么这种情况, 我愚钝只能设置成fitxy吧,如图
好的 被拉伸了。
这个时候 我就像大佬那样,设置完 也不管拉伸与否,就提交上去了,后来我的老大jack就看出来了,给我指导一番,说出了imageview的神属性,adjustViewBounds 卧槽,真的一设置,就成了,而且 还不用设置了scaleType,真屌。
然后我就去谷歌这个属性,看博客,有人说的是设置了adjustViewBounds,还要必须设置maxWidth,maxHeight这两个属性,但是下面就是官网和源码上的setxxx这个属性的方法,看了注释的意思也很明确就是就是让iamageview符合内部图片的大小,但是网上别的文章就说 设置了adjustViewBounds,还要必须设置maxWidth,maxHeight这两个属性,跟这个不同,还是去看一下源码是怎么做到吧.
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);
}
}
有人说会不会是背景颜色原因(并不是,我只是为了突出效果显示,其实你可以试试,把背景去掉)
那就去看看源码吧,理清一下思路
设置了adjustViewBounds那么imageview就会变得很听话,不设置,即使设置了scaleType还是没卵用,那么adjustViewBounds肯定有关键的作用,所以去imageview的源码里看看,
那就全局搜索adjustViewBounds
首先看到的是mAdjustViewBounds默认是false没有开启,
然后是set,get方法
然后是在onMeasure中用到了
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
resolveUri(); // 验证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;
//不为空,那么就进行赋值上drawable的大小
// We are supposed to adjust view bounds to match the aspect
// ratio of our drawable. See if that is possible.
//设置了adjustViewBounds,就会调整比例,将view的比例设置成
//drawable的比例,所以能够完美展示。同时注意resizeWidth,只有当view当测量模式不是Exactly,就是(match_parent,和精准当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;
//如果是精准当size,那么就得重新测量了,同时还需要设置adjustViewbounds属性才行,因为只有设置了adjustViewBounds属性了才能对reseiz这两个值进行赋值,别的地方没有赋值
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);
//如果设置了adjustViewBounds,然后根据比例对需要对宽高进行缩放,是等比例缩放。
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 {
//如果没有设置,那么久根据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);
}
总结
其实adjutViewBounds 的作用就是当Imageivew的宽或者设置成了At_Most模式后,会让imageview的大小等比缩放变成了drawable的大小.
那么为什么imageview设置成wrap_content,会多出来宽的呢?去看源码知道了,imageview的width,height是mDrawable的width,height,那么这个drawable的赋值是d.getIntrinsicHeight();,和d.getIntrinsicWidth();这个得来的,继续追,发现这个是bitmapdrawable,然后看源码
private void computeBitmapSize() {
final Bitmap bitmap = mBitmapState.mBitmap;
if (bitmap != null) {
mBitmapWidth = bitmap.getScaledWidth(mTargetDensity);
mBitmapHeight = bitmap.getScaledHeight(mTargetDensity);
} else {
mBitmapWidth = mBitmapHeight = -1;
}
}
这是赋值,他会根据mTargetDensity(屏幕的比例)这个属性对bitmap的宽高进行缩放,所以导致了上诉情况。