0赞
赏
赞赏
更多好文
“一个 Drawable 用得好,胜过十行自定义 View”
—— 某位深夜改需求的 Android 老兵
🌟 开场白:你以为 Drawable 只是“图片”?
“把这张图设为按钮背景”——这是新手对 Drawable 的初印象。
但资深开发者知道:Drawable 是 Android UI 的“隐形骨架”。
从水波纹反馈到动态进度条,从状态切换到内存优化,它默默撑起 80% 的视觉体验。
今天,我们抛开“Drawable=图片”的刻板印象,带你系统梳理 Android Drawable 家族全图谱!文末附 实战避坑指南+性能优化清单,建议收藏⭐
📚 Drawable 家族全景图(附使用场景+代码片段)
🔷 基础图像类
| 类型 | 核心能力 | 典型场景 | 一句话提示 |
|---|---|---|---|
| BitmapDrawable | 封装 PNG/JPEG 等位图 | App 图标、背景图 | 注意内存!大图用 inSampleSize 压缩 |
| NinePatchDrawable | .9.png 可拉伸区域定义 | 聊天气泡、按钮背景 | 拉伸区/内容区标记得精准,否则变形 |
| VectorDrawable | XML 矢量图(无限缩放) | Material Design 图标 | 低版本用 app:srcCompat + Support Library |
<!-- vector 示例:心形图标 -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF0000"
android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5C2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"/>
</vector>
🔷 形状与色彩类
| 类型 | 核心能力 | 典型场景 | 高频技巧 |
|---|---|---|---|
| GradientDrawable | XML 定义形状+渐变(<shape>) | 圆角按钮、进度条底 | android:useLevel="false" 避免被当 LevelList 用 |
| ColorDrawable | 纯色填充 | 临时占位背景、分割线 | new ColorDrawable(Color.TRANSPARENT) 快速清背景 |
<!-- 渐变圆角按钮 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#FF6B6B"
android:endColor="#4ECDC4"
android:angle="135"/>
<corners android:radius="12dp"/>
<padding android:left="16dp" android:top="8dp"/>
</shape>
🔷 状态与组合类(🔥 高频考点!)
| 类型 | 核心能力 | 典型场景 | 血泪教训 |
|---|---|---|---|
| StateListDrawable | 按 View 状态切换(<selector>) | 按钮按下/禁用效果 | item 顺序决定优先级! 默认状态放最后 |
| LayerDrawable | 多 Drawable 叠加(<layer-list>) | 带边框头像、徽章 | 用 android:gravity 精准定位子层 |
| LevelListDrawable | 按 level 值切换(如电量/信号) | 电量图标、评分星级 | drawable.setLevel(5000) 动态控制 |
<!-- 按钮状态选择器(正确顺序!) -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:drawable="@color/gray"/>
<item android:state_pressed="true" android:drawable="@color/blue_dark"/>
<item android:drawable="@color/blue"/> <!-- 默认状态必须放最后! -->
</selector>
🔷 动效与变换类
| 类型 | 核心能力 | 典型场景 | 注意事项 |
|---|---|---|---|
| AnimationDrawable | 帧动画(<animation-list>) | 加载动画、表情动图 | start() 必须在 View 可见后调用 |
| TransitionDrawable | 两 Drawable 淡入淡出 | 刷新指示器、主题切换 | startTransition(300) 控制时长 |
| RippleDrawable | 水波纹反馈(API 21+) | Material 按钮点击效果 | 低版本用 ?attr/selectableItemBackground 兼容 |
<!-- 水波纹(带边界) -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<corners android:radius="8dp"/>
<solid android:color="@android:color/white"/>
</shape>
</item>
</ripple>
🔷 进阶工具类
| 类型 | 用途 | 实战价值 |
|---|---|---|
| InsetDrawable | 内边距包裹(替代 padding) | 精确控制 Drawable 显示区域 |
| ClipDrawable | 按 level 裁剪(进度条核心) | 自定义水平/圆形进度条 |
| RotateDrawable | 旋转动画 | 音乐播放旋转图标 |
| ScaleDrawable | 按 level 缩放 | 动态调整图标大小 |
💡 高阶技巧:这些用法让面试官眼前一亮
✅ 技巧1:用 LayerDrawable 实现“带红点的头像”
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/avatar"/>
<item android:right="8dp" android:top="8dp">
<shape android:shape="oval">
<solid android:color="#FF0000"/>
<size android:width="12dp" android:height="12dp"/>
</shape>
</item>
</layer-list>
✅ 技巧2:ClipDrawable 手写进度条(零 View 代码!)
ClipDrawable clip = (ClipDrawable) progressBar.getBackground();
clip.setLevel((int)(progress * 10000)); // level 范围 0~10000
✅ 技巧3:VectorDrawable + AnimatedVectorDrawable = 交互动效
(配合 Shape Shifter 工具生成路径动画,实现“播放→暂停”图标切换)
⚠️ 避坑指南:血泪总结的 5 大雷区
| 坑点 | 现象 | 解决方案 |
|---|---|---|
| StateList 顺序错乱 | 按下无反馈 | 确保“默认状态”放在 selector 最后 |
| Vector 低版本崩溃 | API<21 闪退 | 启用 vectorDrawables.useSupportLibrary = true |
| AnimationDrawable 不动 | 帧动画卡第一帧 | 在 onWindowFocusChanged 中 start() |
| Shape 内存泄漏 | 复杂渐变卡顿 | 避免在 RecyclerView 高频刷新项中用复杂 Gradient |
| Ripple 无边界 | 水波纹溢出圆角 | 用 <item android:id="@android:id/mask"> 定义裁剪区域 |
🌱 写在最后:Drawable 是“小工具”,更是“大智慧”
- 性能党:用 Shape 代替 PNG 背景,安装包直降 10%+
- 体验党:Ripple + Transition 让交互有温度
- 架构党:自定义 Drawable 封装业务逻辑(如:带 Badge 的 Drawable)
真正的高手,往往在最基础的 API 里藏了最深的功力。
下次当你写android:background时,不妨多问一句:
“这里,Drawable 能做得更好吗?”
💬 互动时间
👉 你用过最巧妙的 Drawable 技巧是什么?
👉 有没有被某个 Drawable 坑到深夜的经历?
📌 延伸阅读
- 《VectorDrawable 兼容性终极指南》
- 《自定义 Drawable:从入门到造轮子》
- 官方文档:Drawable Resources
