安卓Drawable分类

基于你提供的详尽分类框架,我结合最新实践补充底层原理、实用技巧及进阶用法,帮助开发者更系统化地掌握 Drawable 体系:


⚙️ ​一、底层机制与核心原理

  1. Drawable 基类关键方法

    • draw(Canvas canvas):抽象绘制方法,所有子类必须实现(如 BitmapDrawable 绘制位图、ColorDrawable 填充纯色)
    • setBounds(Rect bounds):定义绘制区域,触发 onBoundsChange() 回调
    • setLevel(int level):控制动态效果(如 ClipDrawable 裁剪比例)
    • setState(int[] stateSet):响应视图状态变化(如 StateListDrawable 的按下/聚焦状态)
  2. 资源复用与性能优化

    • 共享资源BitmapDrawable 默认共享位图资源,调用 mutate() 可创建独立副本避免相互影响
    • 自动压缩 :AAPT 工具会优化 res/drawable 中的 PNG 图片(如 256 色转 8 位),若需原图应放 res/raw/

🎨 ​二、进阶分类与使用场景扩展

类别 核心子类 最佳实践
基础图形 ColorDrawable 纯色背景,优先用 @color 资源而非硬编码
ShapeDrawable 矩形/圆角/描边,替代简单图片减少资源体积
GradientDrawable 支持线性/径向/扫描渐变,替代渐变图片
动态响应 StateListDrawable 状态顺序敏感!​从上到下匹配,首个匹配项生效(默认状态应放最后)
RippleDrawable 水波纹效果需嵌套 <item> 定义背景,避免遮盖内容
组合变换 LayerDrawable 图层顺序=绘制顺序,​最后一项显示在最顶层
InsetDrawable 为其他 Drawable 添加内边距,避免文本贴边
ClipDrawable 进度条首选!level 范围 0(全剪)~10000(全显)
矢量与动画 VectorDrawable 图标首选,适配多分辨率屏幕,需兼容库支持 API <21
AnimatedVectorDrawable 路径变形动画,结合 <target> 指定动画作用对象

⚡️ ​三、高频问题解决方案

  1. ​**.9 图片使用规范**​

    • 必须放 res/drawable/mipmap/ 目录无效
    • AS 要求保留黑边(反编译 APK 获取带黑线的原图)
  2. 动态创建技巧

    ini 复制代码
    // 代码创建渐变按钮背景
    val gradient = GradientDrawable().apply {
      shape = GradientDrawable.RECTANGLE
      cornerRadius = 16.dpToPx() // 转换 dp 为像素
      colors = intArrayOf(Color.BLUE, Color.CYAN)
    }
    button.background = gradient
  3. 性能陷阱规避

    • 避免嵌套超过 3 层的 StateListDrawable
    • 复杂图形用 VectorDrawable 替代多张位图

🛠️ ​四、XML 实战示例:带按压效果的渐变按钮

xml 复制代码
<!-- res/drawable/btn_gradient_selector.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 按压状态:深色渐变 -->
    <item android:state_pressed="true">
        <shape android:shape="rectangle">
            <corners android:radius="8dp" />
            <gradient
                android:startColor="#FF416C"
                android:endColor="#FF4B2B"
                android:angle="45"/>
        </shape>
    </item>
    <!-- 默认状态:亮色渐变 -->
    <item>
        <shape android:shape="rectangle">
            <corners android:radius="8dp" />
            <gradient
                android:startColor="#36D1DC"
                android:endColor="#5B86E5"
                android:angle="45"/>
        </shape>
    </item>
</selector>

通过 android:angle 控制渐变方向,state_pressed 区分状态


💎 ​总结建议

  • 优先矢量 :图标/简单图形用 VectorDrawable,减少分辨率适配成本
  • 慎用位图 :复杂图片选 WebP 格式,.9.png 用于特殊拉伸需求
  • 状态精简StateListDrawable 的状态匹配链尽量简短
  • 组合创新LayerDrawable + ClipDrawable 可实现动态进度条+背景叠加

更多实践案例可参考 Android Developers 官方资源 或 菜鸟教程示例。

相关推荐
一起搞IT吧39 分钟前
内存泄漏系列专题分析之三十二:高通相机CamX ION/dmabuf内存管理机制CmdBuffer
android·图像处理·数码相机
whysqwhw3 小时前
安卓内存优化
android
用户2018792831674 小时前
TabLayout禁止滑动 + 左对齐排列实现
android
_祝你今天愉快5 小时前
SparseArray & ArrayMap
android·数据结构
2501_916007475 小时前
Charles中文版抓包工具使用指南 提高API调试和网络优化效率
android·ios·小程序·https·uni-app·iphone·webview
叽哥6 小时前
flutter学习第 6 节:按钮与交互组件
android·flutter·ios
xzkyd outpaper6 小时前
Android视图状态以及重绘
android
用户2018792831676 小时前
为什么 Tab 文字默认会全大
android
用户2018792831676 小时前
Tablayout默认情况下,标签为什么会比文字宽?
android