Android ColorStateList 与StateListDrawable

本文探讨了Android中的ColorStateList和StateListDrawable的继承关系、用法、共同点和不同点。它们都是根据状态进行选择,但ColorStateList处理颜色,而StateListDrawable处理Drawable。在XML中,ColorStateList位于res/color目录,StateListDrawable位于res/drawable目录。当设置背景颜色时,ColorStateList会转化为ColorDrawable。理解这两种组件的区别对于Android开发至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

继承关系

  • ColorStateList
.
|--Object
      ├─ColorStateList
  • StateListDrawable
.
|--Object
|   ├─Drawable
|       ├─ColorDrawable
|       ├─**StateListDrawable**

用法

  • ColorStateList

    • 多状态颜色的ColorStateList

      java:

      // 颜色数组
      int[] colors = new int[]{color, color1, color2, color3, color4, color5};
      
      // 颜色数组对应的状态
      int[][] states = new int[6][];
      states[0] = new int[]{android.R.attr.state_checked, android.R.attr.state_enabled};
      states[1] = new int[]{android.R.attr.state_enabled, android.R.attr.state_focused};
      states[2] = new int[]{android.R.attr.state_enabled};
      states[3] = new int[]{android.R.attr.state_focused};
      states[4] = new int[]{android.R.attr.state_window_focused};
      states[5] = new int[]{};
      ColorStateList colorList = new ColorStateList(states, colors)

      xml:

      <!--test.xml-->
      <?xml version="1.0" encoding="utf-8"?>
      <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:color="@color/colorTextWhite" android:state_enabled="false"/>
        <item android:color="@color/colorAccent" />
      </selector>
    • 单种颜色ColorStateList

      java:

      int color = 0xff00ff00
      ColorStateList colorList  = ColorStateList.valueOf(color);

      xml:

      <?xml version="1.0" encoding="utf-8"?>
      <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:color="@color/colorAccent" />
      </selector>
    • 注意

      如果一个xml的方式创建,xml文件要位于res/color/目录,而不是 res/drawable/ 目录。

  • StateListDrawable

    • xml

      <?xml version="1.0" encoding="utf-8"?>
      <selector xmlns:android="http://schemas.android.com/apk/res/android">
          <item android:drawable="@color/colorPrimaryDark" android:state_checked="true" />
          <item android:drawable="@color/colorAccent" />
      </selector>
    • java

      StateListDrawable sld = new StateListDrawable();
      sld.addState(new int[]{android.R.attr.state_checkable},new ColorDrawable(0xfff));
      v.setBackground(sld);
    • 注意

      addState先添加,优先匹配

共同点

  • 两者具有状态属性 ,状态定义在android.R.attr中:

    android:state_pressed=["true" | "false"]
    android:state_focused=["true" | "false"]
    android:state_selected=["true" | "false"]
    android:state_checkable=["true" | "false"]
    android:state_checked=["true" | "false"]
    android:state_enabled=["true" | "false"]
    android:state_window_focused=["true" | "false"] 
  • 选择方式

    都是至上而下匹配(xml从上到下,java中int[] 从0~n),如果单个item中有两张状态声明,则同时满足两个状态才匹配成功

  • 默认值

    当所有条件都不满足的时候,会返回默认值。也就是最后一个值。

不同点

  • xml文件位置

    ColorStateList 对应的xml文件位于res/color中

    StateListDrawable 对应的xml文件位于res/drawable中

  • 用途

    ColorStateList 用于颜色选择

    StateListDrawable 用于Drawable选择

思考

  • color,ColorStateList 与 ColorDrawable

    color是一种颜色,ColorStateList 是根据状态的多种颜色,ColorDrawable是一个可绘制对象。

    color可以转化为ColorStateListcolor也可以转化为ColorDrawableColorStateListColorDrawable没关系。

    假如我们要设置背景颜色:

    public class View{
      private Drawable mBackground;
      public void setBackgroundColor(@ColorInt int color) {
          if (mBackground instanceof ColorDrawable) {
              ((ColorDrawable) mBackground.mutate()).setColor(color);
              computeOpaqueFlags();
              mBackgroundResource = 0;
          } else {
              setBackground(new ColorDrawable(color));
          }
      }
    }

    color首先会被转换为ColorDrawable , 因为绘制背景时不会有一个Paint去绘制这个颜色。而是Drawable直接绘制在Canves上。

  • 为什么 同样是<select></select>标签,内容是color和内容是drawble要分别放在res/color/ 和 res/drawable/文件夹?

    res/drawable/test_color.xml

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
      <item android:color="@color/colorTextWhite" android:state_enabled="false" />
      <item android:color="@color/colorAccent" android:state_enabled="true" />
    </selector>

    res/drawable/test_drawable.xml

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
      <item android:drawable="@drawable/img_a" android:state_checked="true"  />
      <item android:drawable="@drawable/img_b" android:state_checked="false"/>
    </selector>

    首先他们对应的java类不同,test_drawable.xml 使用时会反射生成 StateListDrawable,而test_color.xml 使用时会反射生成ColorStateList.而ColorStateList并不时drawable的子类,也就是说它不是一个drawable。也就没理由放到drawable目录下。

  • 为什么 res/value/colors/xml 下的颜色资源 和res/color/xx.xml下的资源可以都使用 @color/xx 使用?

    res/value/colors/xml 下的color是一个单一颜色值

    res/color/**.xml下是和状态有关的多个颜色值.

    他们的关系类似 单个image是一个drawble 而 StateListDrawable 是 和状态有关的多个drawable,都是drawable所以就@drawable。

    类似,都是用来表示颜色,所以就都@color

  • 为什么同样是设置颜色,setBackground使用 res/drawable/ , 而setTextColor使用res/color/?

    setBackground需求的参数是Drawable,如果是颜色,颜色会被转换成ColorDrawable。如果需要多个颜色,使用res/drawable/下的selector,转化为StateListDrawable,每个state都是一个ColorDrawable。也就是说,这里面的color一定转为ColorDrawable使用。

    setTextColor需求的参数是color ,res/color/colors.xmlres/color/**.xml都会转化为ColorStateListColorStateList用来提供color。

ColorStateList与StateListDrawable设计思路是一样的,只是一个用于color,一个用于drawable

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值