Androidでリスト表示する時に、一緒に画像やチェックボックスなんかを入れるときは
オリジナルのアダプタを作ってやるのが定石みたいな感じだけど、意外とめんどくさいし変にハマったりすることがある。
今回はチェックボックスを入れるときの注意点的なもの。
基本的にはオリジナルのアダプタを作る時はArrayAdapterを継承して作ることが多いけど、データベースにアクセスして検索結果をリストアップするなんて時は、Cursorを使うことになるのでSimpleCursorAdapterが便利です。
で、アダプタを作る時にgetViewをオーバーライドして要求されたViewを返すわけだけど
このgetViewでちょっと注意が必要で、
public View getView(int position,
View convertView,
ViewGroup parent)
上の2番目の引数がnullじゃないときは、どこかの行で使われたviewで、必ずしもpositionの場所で
使われているViewとは限らないって事があります。
なのでconvertViewがnullの場合は新しくViewを作って追加、nullじゃなければ一回どこかで使われたViewを使いまわすっていうやり方をする必要があるんですが、
これはつまりCheckBoxを入れた場合も一緒で、positionが一緒でもgetViewで帰ってくるCheckBoxが同じオブジェクトとは限らないので、チェックしたところと違うところもチェックがついてるなんて事がおきます。
たいてい画面に映りきっていない部分が一緒にチェックされたりします。
コレを防ぐためにどこの行のCheckBoxがチェックされていたのかって言う情報を保持しておく必要があります。
public class CursorAdapter extends SimpleCursorAdapter {
private Listchecked;
@Override
public View getView(final int position,View v,ViewGroup parent){
View returnedView = super.getView(position, v, parent);
LinearLayout l = (LinearLayout)returnedView;
CheckBox cb = (CheckBox)l.findViewById(R.id.checkbox);
cb.setOnCheckedChangeListener(
new CompoundButton.OnCheckedChangeListener(){
@Override
public void onCheckedChanged(CompoundButton arg0, boolean arg1) {
// TODO Auto-generated method stub
checked.set(position, arg1); //チェックが変わるたびに
//位置と状態を保存
listener.onCheckedChanged(arg0, arg1);
}
});
cb.setChecked(checked.get(position));//positionからチェック
//の状態を取り出す
cb.setFocusable(false);
return returnedView;
}
}
}
※他の部分は省略してます。
getViewにはいる度にリスナーをセットし、Boolean用のリストを作っておき、チェックの状態に変化があった時に位置とチェックの状態を保存しています。
で、Viewを返す前にCheckBoxの状態をpositionにあう状態に変更してます。
これで変なところにチェックがつくとかはなくなります。
今回はSimpleCursorAdapterを継承しているのでCheckBox以外の処理は親クラスのgetViewに任せています。
listener.onCheckedChanged(arg0, arg1) は別クラスのOnCheckedChangeListenerで、チェックの状態が変わった時に他に処理をしたい場合はコンストラクタとかの引数としてイベントハンドラのクラスを渡して、むりやりここで呼び出せば使えます。
あと、cb.setFocusable(false)でフォーカスをfalseにしないとリストのほうがクリックできなくなるので、リストのアイテムをクリックできるようにしたい場合はコレをする必要があります。
最近自分で書いたプログラムもわかんなくなっちゃったりするからコメントとかメモとか
残さなくちゃなぁ・・・