ColorStateList はベストマッチではなく最初にマッチした色が適用される

selector タグを使って ColorStateList をつくるとき、次のような定義は期待通りに色が切り替わってくれる。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 押し込まれてるときの色 -->
    <item android:state_pressed="true">
        <color android:color="@android:color/holo_blue_dark" />
    </item>

    <!-- それ以外のときの色 -->
    <item>
        <color android:color="@android:color/holo_orange_dark" />
    </item>
</selector>

もし、この item の定義順を入れ替えて次のようにしてしまうと、常に @android:color/holo_orange_dark が適用されてしまう動きになる。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- それ以外のときの色 -->
    <item>
        <color android:color="@android:color/holo_orange_dark" />
    </item>

    <!-- 押し込まれてるときの色 -->
    <item android:state_pressed="true">
        <color android:color="@android:color/holo_blue_dark" />
    </item>
</selector>

なぜかというと、ColorStateList で色が選ばれるときの挙動として、全てを精査してベストマッチする要素ではなく、上から順番に見ていった結果最初にマッチした状態の色(先の例では何も条件が指定されていない「それ以外のときの色」)が選ばれるため。

developer.android.com

During each state change, the state list is traversed top to bottom and the first item that matches the current state will be used—the selection is not based on the "best match," but simply the first item that meets the minimum criteria of the state.

developer.android.com

Note: The list of state specs will be matched against in the order that they appear in the XML file. For this reason, more-specific items should be placed earlier in the file. An item with no state spec is considered to match any set of states and is generally useful as a final item to be used as a default.

If an item with no state spec is placed before other items, those items will be ignored.

Android Dev Summit '19 で行われたセッション Developing Themes with Style の動画では13分9秒ごろからこの話題について触れられている。

今回は分かりやすくシンプルな例を書いたけれど、設定する条件によって item がさらに増えると、意図しない挙動にハマるかもしれないので、そのときは定義順に気をつけてみると直るかもしれない。