2012年12月5日水曜日

Android CheckedTextView を使うときの注意

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

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

setCheckMarkDrawable(int resid)



setCheckMarkDrawable(Drawable d)

があります。

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

setCheckMarkDrawable(R.drawable.check)

setCheckMarkDrawable(null)

setCheckMarkDrawable(R.drawable.check) ←ここ

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

正しく動くようにするには、
  1. if(isChecked) {  
  2.     ctv.setCheckMarkDrawable(R.drawable.check);  
  3. }  
  4. else {  
  5.     ctv.setCheckMarkDrawable(0);  
  6. }  
のように 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
  1. 112     public void setCheckMarkDrawable(int resid) {  
  2. 113         if (resid != 0 && resid == mCheckMarkResource) {  
  3. 114             return;  
  4. 115         }  
  5. 116   
  6. 117         mCheckMarkResource = resid;  
  7. 118   
  8. 119         Drawable d = null;  
  9. 120         if (mCheckMarkResource != 0) {  
  10. 121             d = getResources().getDrawable(mCheckMarkResource);  
  11. 122         }  
  12. 123         setCheckMarkDrawable(d);  
  13. 124     }  
  14. 125   
  15. 126     /** 
  16. 127      * Set the checkmark to a given Drawable. This will be drawn when {@link #isChecked()} is true. 
  17. 128      * 
  18. 129      * @param d The Drawable to use for the checkmark. 
  19. 130      * 
  20. 131      * @see #setCheckMarkDrawable(int) 
  21. 132      * @see #getCheckMarkDrawable() 
  22. 133      * 
  23. 134      * @attr ref android.R.styleable#CheckedTextView_checkMark 
  24. 135      */  
  25. 136     public void setCheckMarkDrawable(Drawable d) {  
  26. 137         if (mCheckMarkDrawable != null) {  
  27. 138             mCheckMarkDrawable.setCallback(null);  
  28. 139             unscheduleDrawable(mCheckMarkDrawable);  
  29. 140         }  
  30. 141         mNeedRequestlayout = (d != mCheckMarkDrawable);  
  31. 142         if (d != null) {  
  32. 143             d.setCallback(this);  
  33. 144             d.setVisible(getVisibility() == VISIBLE, false);  
  34. 145             d.setState(CHECKED_STATE_SET);  
  35. 146             setMinHeight(d.getIntrinsicHeight());  
  36. 147   
  37. 148             mCheckMarkWidth = d.getIntrinsicWidth();  
  38. 149             d.setState(getDrawableState());  
  39. 150         } else {  
  40. 151             mCheckMarkWidth = 0;  
  41. 152         }  
  42. 153         mCheckMarkDrawable = d;  
  43. 154         // Do padding resolution. This will call setPadding() and do a requestLayout() if needed.  
  44. 155         resolvePadding();  
  45. 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 件のコメント:

コメントを投稿