2012年12月5日水曜日

Android CheckedTextView を使うときの注意

ListView で CHOICE_MODE_SINGLE とか CHOICE_MODE_MULTIPLE とか使うときに、1行のレイアウトとして CheckedTextView を使うことがあると思いますが、チェックマークの切り替えには注意が必要です。

チェックマーク画像を設定するメソッドとして

setCheckMarkDrawable(int resid)



setCheckMarkDrawable(Drawable d)

があります。

例えば、チェックできる行にはチェクマーク画像をセットして、チェックできない行(例えばフラグが立ってるとか、ロックされているなど)にはチェックマーク画像をセットしないようにする場合、 if(isChecked) { ctv.setCheckMarkDrawable(R.drawable.check); } else { ctv.setCheckMarkDrawable(null); } とすると、2回目に R.drawable.check をセットしたとき、

setCheckMarkDrawable(R.drawable.check)

setCheckMarkDrawable(null)

setCheckMarkDrawable(R.drawable.check) ←ここ

で画像がセットされません。ListView の1行のレイアウトに使うと行の View が再利用されるのでこういう状況によくなります。

正しく動くようにするには、 if(isChecked) { ctv.setCheckMarkDrawable(R.drawable.check); } else { ctv.setCheckMarkDrawable(0); } のように null ではなく 0 を渡すようにします。

CheckedTextView のコードをみると、setCheckMarkDrawable(int resid) では、mCheckMarkResource にセットされたリソースID を保持しておいて、新しくセットされたリソースIDがこれと同じ場合はなにも処理をしないようになっています。

http://tools.oesf.biz/android-4.1.2_r1.0/xref/frameworks/base/core/java/android/widget/CheckedTextView.java 112 public void setCheckMarkDrawable(int resid) { 113 if (resid != 0 && resid == mCheckMarkResource) { 114 return; 115 } 116 117 mCheckMarkResource = resid; 118 119 Drawable d = null; 120 if (mCheckMarkResource != 0) { 121 d = getResources().getDrawable(mCheckMarkResource); 122 } 123 setCheckMarkDrawable(d); 124 } 125 126 /** 127 * Set the checkmark to a given Drawable. This will be drawn when {@link #isChecked()} is true. 128 * 129 * @param d The Drawable to use for the checkmark. 130 * 131 * @see #setCheckMarkDrawable(int) 132 * @see #getCheckMarkDrawable() 133 * 134 * @attr ref android.R.styleable#CheckedTextView_checkMark 135 */ 136 public void setCheckMarkDrawable(Drawable d) { 137 if (mCheckMarkDrawable != null) { 138 mCheckMarkDrawable.setCallback(null); 139 unscheduleDrawable(mCheckMarkDrawable); 140 } 141 mNeedRequestlayout = (d != mCheckMarkDrawable); 142 if (d != null) { 143 d.setCallback(this); 144 d.setVisible(getVisibility() == VISIBLE, false); 145 d.setState(CHECKED_STATE_SET); 146 setMinHeight(d.getIntrinsicHeight()); 147 148 mCheckMarkWidth = d.getIntrinsicWidth(); 149 d.setState(getDrawableState()); 150 } else { 151 mCheckMarkWidth = 0; 152 } 153 mCheckMarkDrawable = d; 154 // Do padding resolution. This will call setPadding() and do a requestLayout() if needed. 155 resolvePadding(); 156 }

つまり、
setCheckMarkDrawable(R.drawable.check)
: mCheckMarkResource = R.drawable.check

setCheckMarkDrawable(null)
: setCheckMarkDrawable(int resid) を通らないので mCheckMarkResource = R.drawable.check のまま

setCheckMarkDrawable(R.drawable.check) ←ここ
:mCheckMarkResource が引数の resid と同じなので画像をセットしない = 画像は null のまま

という動作になってしまうのです。。。


0 件のコメント:

コメントを投稿