为什么Android自定义shape Drawable无法作为列表项背景正常显示?
问题原因
- AppCompat兼容组件适配bug:你使用的
LinearLayoutCompat属于v7兼容包组件,新版本AppCompat库对根节点为<shape>的Drawable做自动主题适配、资源复用的逻辑存在缺陷,会导致部分场景下shape不渲染。外层套<layer-list>相当于绕开了针对shape根节点的特殊处理逻辑,所以可以正常显示。 - Drawable共享常量状态污染:Android系统默认同资源ID的Drawable会共享常量状态,如果你项目其他地方修改过
R.drawable.ticketborder对应的Drawable的透明度、颜色等属性,没有调用mutate()方法隔离状态的话,会导致全局所有用到该Drawable的位置都被修改,出现不可见的情况。套<layer-list>后每个实例状态独立,不会被共享状态影响。 - Android Studio构建缓存异常:你提到更新了Android Studio,存在旧的构建缓存没有被正确清理的可能,shape资源的修改没有被打包到最终APK中,而修改资源结构为layer-list后会触发资源重新编译,因此正常生效,你可以尝试清理项目缓存(
Build -> Clean Project+Invalidate Caches / Restart)验证。
动态修改layer-list属性的方法
你可以直接在代码中解析layer-list,取出内层的shape对象修改属性,示例代码如下:
// 从资源中取出layer-list背景 LayerList layerDrawable = (LayerList) ContextCompat.getDrawable(context, R.drawable.ticketborder); // 取出第0个item对应的shape Drawable GradientDrawable shapeDrawable = (GradientDrawable) layerDrawable.getDrawable(0); // 修改填充色 shapeDrawable.setColor(Color.parseColor("#ff00ff00")); // 修改边框,第一个参数为边框宽度(单位px,可自行转换为dp单位适配不同屏幕),第二个参数为边框颜色 shapeDrawable.setStroke(dp2px(context, 4), Color.parseColor("#ffff0000")); // 设置给View作为背景 v.setBackground(layerDrawable);
其中dp转px的工具方法参考:
private int dp2px(Context context, float dpValue) { float density = context.getResources().getDisplayMetrics().density; return (int) (dpValue * density + 0.5f); }
如果你需要频繁修改背景属性,也可以直接代码创建GradientDrawable,不需要定义xml资源,性能更高:
GradientDrawable shapeDrawable = new GradientDrawable(); shapeDrawable.setShape(GradientDrawable.RECTANGLE); shapeDrawable.setColor(Color.GREEN); shapeDrawable.setStroke(dp2px(context, 4), Color.RED); v.setBackground(shapeDrawable);
内容的提问来源于stack exchange,提问作者David Rector
相关产品推荐
相关产品推荐

