clip 标签无法实现进度条效果,因其仅为静态裁剪工具,不响应属性动画、不支持 setlevel() 动态更新、在 android 7.0+ 已被弃用,真机易现模糊失真;正确方案是自定义 view 配合 canvas.cliprect() 与 valueanimator 实现平滑裁剪动画。

clip 标签在 Android XML 中根本不能实现进度条效果
直接说结论:clip 是 ShapeDrawable 的子标签,只支持静态裁剪矩形区域,不响应属性动画、不监听进度变化、无法随 ProgressBar 动态更新。拿它做“图片裁剪进度条”是常见误解——XML 里写不出带进度的裁剪动画。
为什么 clip 不适合做进度条裁剪
它本质是编译期静态裁剪:系统读取 android:clipOrientation 和 android:gravity 后,一次性计算出裁剪矩形并缓存,后续修改 level(比如通过 setLevel())完全无效。实测中即使给 ClipDrawable 套上 AnimatedVectorDrawable,裁剪区域也不会动。
-
clip只在layer-list或shape内部生效,不能独立作为ProgressBar的progressDrawable - Android 7.0+ 对
ClipDrawable的setLevel()调用已标记为 deprecated,官方明确不鼓励用于动态场景 - 真机上常出现裁剪边界模糊、缩放失真,尤其在高密度屏或非整数尺寸下
替代方案:用 BitmapShader + 自定义 View 实现精准裁剪进度
要让一张图随进度从左到右“展开式裁剪”,必须脱离纯 XML,走代码路径。核心是复用 Canvas.clipRect() 配合 drawBitmap(),而不是依赖 clip 标签。
- 继承
View,重写onDraw(),先调用canvas.clipRect(left, top, right, bottom)划定当前可见区域 -
right = getWidth() * progress(progress ∈ [0,1]),这样裁剪宽度随进度线性增长 - 再用
canvas.drawBitmap(mBitmap, null, getBounds(), paint)绘制原图,自动适配裁剪区 - 触发刷新用
ValueAnimator.ofFloat(0f, 1f),避免Handler或轮询导致卡顿
示例关键行:
canvas.clipRect(0, 0, (int) (getWidth() * mProgress), getHeight());
如果非要用 XML 驱动,只能退回到帧动画或遮罩层模拟
硬要保 XML,唯一可行的是用两层叠加:底层放完整图,上层用 layer-list 做一个渐变宽度的遮罩色块(例如 shape + size + solid),再通过 ProgressBar 的 progressDrawable 切换不同宽度的 layer。但这不是裁剪,是视觉欺骗。
- 需预设 N 个固定宽度的 drawable(如
clip_0.xml到clip_100.xml),体积膨胀明显 - 进度跳变时会卡顿,因为
LayerDrawable切换不支持插值 - 遮罩色和背景色稍有差异就会露边,尤其圆角图或透明 PNG
真正需要平滑裁剪动画的地方,clip 标签就是错的起点——它连最基本的「随进度变化」都做不到。










