.9图和padding冲突分析

一、 背景

有个需求出了个bug,一个TextView的宽度是根据文本宽度和padding算出来赋值的,但是当textview的背景是.9图的时候,文本居然显示不全。
why?
咨询了大佬,可能是.9图的问题。

二、 分析过程

迷茫

断点之后发现,textView莫名其妙多了1dp的paddingRight
大概意思就是这样:
在这里插入图片描述

看了xml和代码,非常确信没有设置paddingRight

有点头绪

那这个paddingRight是哪儿来的?
从其他同事那了解到可能是.9图引起的,于是去搜了一下相关的文章。
确实,如果.9图有padding的话,.9图的padding会覆盖掉view的padding。

但是,我又想起来,这个textview我给它设置了左边距,为啥左边没有覆盖掉?
小小的脑袋,大大的疑惑…

新的疑问

之前改bug的时候,加了一个setPadding的方法,但是发现setBackground之后,左边距就不是我设置的值了。
把setPadding注释掉,左边距又ok了。
然后我想到我在xml里面设置过左边距,难道是xml设置了就不会影响?

现在需要排查的有以下几个点:

  1. 绘制的时候,padding是怎么来的?
  2. setBackground的时候发生了什么,为什么会覆盖掉padding?
  3. setPadding做了什么,为什么通过这个方法设置的padding会被覆盖?
  4. xml设置padding是怎么设置的,为什么不会被覆盖?

三、 源码分析

以左边距为例,右边距同理。

1.绘制的时候,padding怎么来的?

直接找到onDraw()

int paddingLeft = mPaddingLeft;

final boolean offsetRequired = isPaddingOffsetRequired();
if (offsetRequired) {
    paddingLeft += getLeftPaddingOffset();
}

int left = mScrollX + paddingLeft;
int right = left + mRight - mLeft - mPaddingRight - paddingLeft;

mPaddingLeft赋值的地方有四个:
在这里插入图片描述所以,要么就是mUserPaddingStart,要么就是mUserPaddingLeftInitial

2. setBackground的时候发生了什么,为什么会覆盖掉padding?

     if (background.getPadding(padding)) { // 背景有padding
                resetResolvedPaddingInternal();

                switch (background.getLayoutDirection()) {
                    case LAYOUT_DIRECTION_RTL:
                        mUserPaddingLeftInitial = padding.right;
                        mUserPaddingRightInitial = padding.left;
                        internalSetPadding(padding.right, padding.top, padding.left, padding.bottom);
                        break;
                    case LAYOUT_DIRECTION_LTR:
                    default:
                        mUserPaddingLeftInitial = padding.left;
                        mUserPaddingRightInitial = padding.right;
                        internalSetPadding(padding.left, padding.top, padding.right, padding.bottom);
                }
                mLeftPaddingDefined = false;
                mRightPaddingDefined = false;
            }

如果背景里面有padding,就会把mUserPaddingLeftInitial设置为背景的paddingLeft
所以,如果绘制时候的padding是mUserPaddingLeftInitial,就会发生.9图padding覆盖view的padding的情况。

3. setPadding做了什么,为什么通过这个方法设置的padding会被覆盖?

public void setPadding(int left, int top, int right, int bottom) {
    resetResolvedPaddingInternal();

    mUserPaddingStart = UNDEFINED_PADDING;
    mUserPaddingEnd = UNDEFINED_PADDING;

    mUserPaddingLeftInitial = left;
    mUserPaddingRightInitial = right;

    mLeftPaddingDefined = true;
    mRightPaddingDefined = true;

    internalSetPadding(left, top, right, bottom);
}

mUserPaddingStart重置了,同时给mUserPaddingLeftInitial赋值。

1中讲到,绘制时的paddingLeft不是mUserPaddingStart,就是mUserPaddingLeftInitial

mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial;

如果mUserPaddingStart<0,那么 mPaddingLeft = mUserPaddingLeftInitial
很明显,用setPadding方法设置了边距,此时mUserPaddingStart被重置,mPaddingLeft的取值就是mUserPaddingLeftInitial的值。setBackgroud之后,backgroud的paddig赋值给了mUserPaddingLeftInitial,导致绘制时的paddingLeft为background的paddingLeft,不是预期的表现。

4.xml设置padding是怎么设置的,为什么不会被覆盖?

xml中设置左边距有两种设置方法,paddingLeftpaddingStart

case com.android.internal.R.styleable.View_paddingLeft:
    leftPadding = a.getDimensionPixelSize(attr, -1);
    mUserPaddingLeftInitial = leftPadding;
    leftPaddingDefined = true;
    break;
case com.android.internal.R.styleable.View_paddingStart:
    startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING);
    startPaddingDefined = (startPadding != UNDEFINED_PADDING);
    break;
...    
mUserPaddingStart = startPadding;
...
if (!mLeftPaddingDefined && startPaddingDefined) {
    leftPadding = startPadding;
}
mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial;

逻辑大概就是:
如果是设置的paddingStart,那么mUserPaddingLeftInitialmUserPaddingStart都会赋值;如果是设置的paddingLeft, 那么mUserPaddingStart不会赋值。
确认了一下xml中的边距是paddingStrat,符合预期。修改为paddingLeft打包之后,就会被覆盖。

四、 结论

view的backgroud如果有padding,会覆盖掉view设置的paddingLeftpaddingRight
如果想要不被覆盖,可以用paddingStartpaddingRight

更多思考:
虽然设置paddingStartpaddingRight可以解决问题。但是,这个坑还是比较容易踩。
首先,作为开发,不一定会去仔细了解设置提供的资源是不是.9图,有没有padding;
其次,设置的时候,更多的时候关注的是有padding的情况,比如说这次的坑,我只设置了paddingStart,右边又没有边距,谁会多此一举给它设置paddingRight=0呢,所以多出来一个1dp的右边距。
然后,虽然说现在不推荐用paddingLeft,但不推荐归不推荐,用还是可能用的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值