カスタムListViewで選択中の色が変わらないトラブル 
火曜日, 11月 23, 2010, 01:42 PM - Android
久しぶりに思いっきり嵌ったので整理してみた。

やりたいこと
行要素にカスタムViewを使ったListViewで、
チェック中の行は色を変えたい。
カスタムViewであることが味噌です。


これをクリックしてチェックすると色が変わるようにしたい。
カスタムViewだとこれが変わらずに難儀した、、。


色はselectorを使ったdrawableで指定したい。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 押されているときの色 -->
<item android:state_pressed="true" android:drawable="@color/green" />

<!-- チェックされた時の色 -->
<item android:state_checked="true" android:drawable="@color/blue" />

<!-- トラックボールなどで動かしたときに対象になったときの色(チェックの有無ではない) -->
<item android:state_selected="true" android:drawable="@color/white" />

<!-- 何につかうんだろう? -->
<item android:state_focused="true" android:drawable="@color/red" />

<!-- それ以外 -->
<item android:drawable="@color/black" />
</selector>


トラブルの現象
通常ではListViewの行要素にselector入りのdrawableを指定した
CheckedTextViewを指定するとチェック時に色が変わる。
しかし、カスタムViewを使うとチェック時でも色が変わらない。

原因
通常では行要素にCheckedTextViewを使うが、
こいつがCheckableインターフェースを実装していて、
そのインターフェース内の処理で描画を変えていることが判明。
しかし、自分の作ったカスタムViewは
そういう作りになっていなかったため色が変わらなかった。

対処
カスタムViewにCheckableインターフェースを実装し、
setCheckedなどのメソッド内で描画を切り替える処理を入れる。
カスタムViewのクラスであるCheckableLinearLayoutを作成した。
package net.cattaka.listviewtest;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.Checkable;
import android.widget.LinearLayout;

public class CheckableLinearLayout extends LinearLayout implements Checkable {
private boolean checked;
private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };

public CheckableLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}

public CheckableLinearLayout(Context context) {
super(context);
}

@Override
public boolean isChecked() {
return checked;
}

@Override
public void setChecked(boolean checked) {
if (this.checked != checked) {
this.checked = checked;
refreshDrawableState();
}
}

@Override
public void toggle() {
this.checked = !this.checked;
refreshDrawableState();
}

@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
}


まとめ
Andriodの描画をselectorで切り替えるのは便利だけど、
ところどころ特定のViewの中の独自処理で切り替えられているのがあるので、
selectorでやればいいやと信用していると痛い目に遭う、、と。
勘弁してよ・・・(´・ω・)


今回のテストコードはこちら
ListViewTest.zip(Eclipseのプロジェクト)


コメント