Android View背景与Shape
某个view需要有点击、焦点、选中的背景反馈是一般使用selector设置各个状态时的背景色。每一个item设置纯色一般比较少见,比较多的是使用bitmap或者shape,如果是bitmap很好理解,状态变化时直接切换渲染的图片就OK,但比较好的方式是用shape自定义图形。 这样做有两点好处,第一能够减小APK包的大小,现在的App很多已经是20+M,对用户的更新造成诸多不便,所以保持App大小很重要,其次能够避免图片平铺拉伸的处理,虽然.9图片从一定程度上保证了屏幕尺寸的兼容。
Shape使用时要注意Padding标签。
在Shape XML中定义了Padding并且此Shape作为某个View的Background时,View就不需要再设置android:padding,因为两者会产生冲突。 源代码分析可见冲突点:
View.java
setBackgroundDrawable()主要读取Drawable的Padding来设置当前View的Padding
------
if (background != null) {
Rect padding = sThreadLocal.get();
if (padding == null) {
padding = new Rect();
sThreadLocal.set(padding);
}
resetResolvedDrawables();
background.setLayoutDirection(getLayoutDirection());
if (background.getPadding(padding)) { // 读取背景图的Padding
resetResolvedPadding(); // 重置当前View的Padding
switch (background.getLayoutDirection()) {
case LAYOUT_DIRECTION_RTL:
mUserPaddingLeftInitial = padding.right; //重置View初始化Padding
mUserPaddingRightInitial = padding.left;
internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); //写入View Padding值
break;
case LAYOUT_DIRECTION_LTR:
default:
mUserPaddingLeftInitial = padding.left;
mUserPaddingRightInitial = padding.right;
internalSetPadding(padding.left, padding.top, padding.right, padding.bottom);
}
mLeftPaddingDefined = false; //将原有Padding置为false
mRightPaddingDefined = false;
}View.java
----------
public void setPadding(int left, int top, int right, int bottom) {//直接设置View的Padding
resetResolvedPadding(); //重置View的Padding
mUserPaddingStart = UNDEFINED_PADDING;
mUserPaddingEnd = UNDEFINED_PADDING;
mUserPaddingLeftInitial = left;
mUserPaddingRightInitial = right;
mLeftPaddingDefined = true;
mRightPaddingDefined = true; //将Padding数据置为true
internalSetPadding(left, top, right, bottom); //写入Padding值
}
通过setBackground() 和setPadding()这两个方法的分析可以看到,Padding最终生效的值,取决于两个方法的调用顺序,按照View读取XML的顺序是先读取背景再读取Padding,与XML中标签的先后顺序无关,但如果在Java代码中就取决于两个方法的调用顺序了。