layer-list 中 bitmap 的 tilemode 不生效,主因是结构错误、api 版本过低、资源尺寸不合理或容器尺寸不足。

layer-list 里 bitmap 的 tileMode 不生效?先看是否用了错误的 root 标签
很多同学写完 tileMode="repeat" 发现图片根本没平铺,第一反应是属性写错了——其实更大概率是 XML 结构本身就不对。layer-list 是容器,它不直接支持 tileMode;真正要设平铺的必须是子节点里的 bitmap,且这个 bitmap 还得是直接子元素(不能套在 item 里再加别的包装)。
- ✅ 正确结构:
<layer-list><bitmap android:src="@drawable/pattern" android:tilemode="repeat"></bitmap></layer-list> - ❌ 错误结构:
<layer-list><item><bitmap ...></bitmap></item></layer-list>—— 这样tileMode会被忽略 - ⚠️ 注意:
item可以存在,但仅当它用android:drawable引用外部 drawable,而不是把bitmap嵌在里面
tileMode="repeat" 在 Android 低于 API 21 上会崩溃?是的,得降级处理
tileMode 的完整取值(repeat、mirror、clamp)从 API 21(Lollipop)才开始支持。如果你的 minSdkVersion ,运行时遇到 <code>Resources$NotFoundException 或 XmlPullParserException,基本就是这个原因。
- 兼容方案:为低版本单独建
res/drawable-v20/目录,把带tileMode的 XML 放进去;高版本用它,低版本回退到静态切图或代码层 Canvas 平铺 - 别指望
tools:targetApi="21"能绕过编译检查——它只影响 lint,运行时照样崩 -
clamp行为在不同系统版本间也有差异:API 21–22 对宽高不整除时的边缘处理不一致,建议测试真机而非仅模拟器
为什么设置了 tileMode 却只平铺了一次?检查 bitmap 的 intrinsic size 和容器尺寸
平铺是否“可见”,取决于两个条件:一是 bitmap 自身有没有明确尺寸(intrinsic width/height),二是它所在的 View 或背景容器是否足够大。如果 @drawable/pattern 是一个 1×1 像素的纯色 PNG,系统可能把它当成“无尺寸”资源,导致平铺逻辑不触发。
- 确保源图至少有合理像素尺寸(比如 8×8 或 16×16),避免单像素图
- 别依赖
android:gravity或android:scaleType来“撑开”平铺效果——这些对layer-list背景无效 - 如果用作 View 的
android:background,注意该 View 的实际宽高;若宽高是wrap_content且内容很小时,你根本看不到重复效果 - 调试技巧:临时把
tileMode改成clamp,再对比显示效果,能快速判断是不是尺寸问题
XML 平铺和代码层 Canvas.drawBitmapMesh 效果不一样?因为底层机制完全不同
XML 中的 tileMode 是由 Skia 渲染引擎在 GPU 层做的纹理重复,轻量且高效;而手动用 Canvas.drawBitmap 配合循环绘制,是 CPU 层逐块提交,不仅慢,还容易因坐标计算误差导致接缝。
- 性能上:XML 平铺几乎零额外开销;循环绘制在列表滚动时可能掉帧
- 精度上:XML 方式自动对齐像素边界;手动画容易偏移半像素,尤其在高倍屏上出现模糊或白线
- 例外场景:需要动态控制平铺偏移(比如视差滚动)或混合多种模式时,才值得放弃 XML,改用
Shader+BitmapShader配合Paint.setShader()
真正难调的不是怎么写 tileMode,而是它什么时候被静默忽略——结构嵌套、API 版本、资源尺寸、宿主 View 大小,四个点只要一个没对,就白忙活。










