转载网址:http://blog.csdn.net/cb269267/article/details/10065709
今天发现了一个比较坑爹的bug,得出的结论如下,不要轻易相信Android的api。
当你调用setBackgroundResource(id)的时候实际上是调用的setBackgroundDrawable(d)
源码如下:
- /**
- * Set the background to a given resource. The resource should refer to
- * a Drawable object or 0 to remove the background.
- * @param resid The identifier of the resource.
- * @attr ref android.R.styleable#View_background
- */
- @RemotableViewMethod
- public void setBackgroundResource(int resid) {
- if (resid != 0 && resid == mBackgroundResource) {
- return;
- }
- Drawable d= null;
- if (resid != 0) {
- d = mResources.getDrawable(resid);
- }
- setBackgroundDrawable(d);
- <span style="color:#ff6666;">mBackgroundResource = resid;</span>
- }
然后在setBackgroundDrawable(d)的时候,实际上它是将backgroundDrawable的padding设置成了这个view的padding的。
源码如下:
- /**
- * Set the background to a given Drawable, or remove the background. If the
- * background has padding, this View's padding is set to the background's
- * padding. However, when a background is removed, this View's padding isn't
- * touched. If setting the padding is desired, please use
- * {@link #setPadding(int, int, int, int)}.
- *
- * @param d The Drawable to use as the background, or null to remove the
- * background
- */
- public void setBackgroundDrawable(Drawable d) {
- if (d == mBGDrawable) {
- return;
- }
- boolean requestLayout = false;
- mBackgroundResource = 0;
- /*
- * Regardless of whether we're setting a new background or not, we want
- * to clear the previous drawable.
- */
- if (mBGDrawable != null) {
- mBGDrawable.setCallback(null);
- unscheduleDrawable(mBGDrawable);
- }
- if (d != null) {
- Rect padding = sThreadLocal.get();
- if (padding == null) {
- padding = new Rect();
- sThreadLocal.set(padding);
- }
- if (d.getPadding(padding)) {
- switch (d.getResolvedLayoutDirectionSelf()) {
- case LAYOUT_DIRECTION_RTL:
- setPadding(padding.right, padding.top, padding.left, padding.bottom);
- break;
- case LAYOUT_DIRECTION_LTR:
- default:
- setPadding(padding.left, padding.top, padding.right, padding.bottom);
- }
- }
- // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or
- // if it has a different minimum size, we should layout again
- if (mBGDrawable == null || mBGDrawable.getMinimumHeight() != d.getMinimumHeight() ||
- mBGDrawable.getMinimumWidth() != d.getMinimumWidth()) {
- requestLayout = true;
- }
- d.setCallback(this);
- if (d.isStateful()) {
- d.setState(getDrawableState());
- }
- d.setVisible(getVisibility() == VISIBLE, false);
- mBGDrawable = d;
- if ((mPrivateFlags & SKIP_DRAW) != 0) {
- mPrivateFlags &= ~SKIP_DRAW;
- mPrivateFlags |= ONLY_DRAWS_BACKGROUND;
- requestLayout = true;
- }
- } else {
- /* Remove the background */
- mBGDrawable = null;
- if ((mPrivateFlags & ONLY_DRAWS_BACKGROUND) != 0) {
- /*
- * This view ONLY drew the background before and we're removing
- * the background, so now it won't draw anything
- * (hence we SKIP_DRAW)
- */
- mPrivateFlags &= ~ONLY_DRAWS_BACKGROUND;
- mPrivateFlags |= SKIP_DRAW;
- }
- /*
- * When the background is set, we try to apply its padding to this
- * View. When the background is removed, we don't touch this View's
- * padding. This is noted in the Javadocs. Hence, we don't need to
- * requestLayout(), the invalidate() below is sufficient.
- */
- // The old background's minimum size could have affected this
- // View's layout, so let's requestLayout
- requestLayout = true;
- }
- computeOpaqueFlags();
- if (requestLayout) {
- requestLayout();
- }
- mBackgroundSizeChanged = true;
- invalidate(true);
- }
再回去看第一段源码的红色那行,你还标注了让人传个参数0就是去掉背景,TM的你就将mBackgroundResource设置成0就拍拍屁股走人了,之前你做过的操作你干嘛不还原呢?你默默地把padding改了,但是你不敢默默地把padding改回去,你偷懒写代码,连函数说明都懒得注明这情况
在此使劲拍你一砖