fc2ブログ

戌印-INUJIRUSHI- (Androidあれこれ)

Androidのプログラミングをメインにしてます。記事に貼られたソースコードはダブルクリックすることで行番号をはずしてコピーすることができます。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
15
17
18
19
20
21
22
23
24
25
26
27
28
29
02

カスタマイズしたListViewに設定したCheckBoxのon/offを行全体で行う

今回はカスタマイズした ListViewCheckBox を乗せたときの on/off 切替を行選択時に行う方法の紹介。

ListView(の項目)にCheckBoxを乗せた場合、CheckBoxのon/off切替はCheckBoxをクリックした時だけになります。
しかもCheckBoxが項目のフォーカスを奪ってしまっているため、onItemClickイベントが発生しなくなっています

そこで、CheckBoxが項目から奪っているフォーカスを項目にお返しし、onItemClickイベントでCheckBoxの on/off を切り替えるようにします。
これはレイアウトの <CheckBox> に以下の2つの属性を追加することで対応できます。

android:clickable="false"
 CheckBoxにフォーカスを当たらなくし、onItemClickイベントを発生するようにします。
android:focusable="false"
 CheckBoxのクリック時にチェックの on/off 切り替えを無効にします。

※android:clickable="false"だけ追加してandroid:focusable="false"を忘れるとCheckBoxが項目からフォーカスを奪ったままクリックできない(イベントを起こせない)状態になります

以下、サンプルソース。
アダプタとデータは前回の記事『ListViewに編集可能なViewを追加する』のを使用しています。

----------------------------------------------------------------------
リストの項目のレイアウト
res/layout/sample_row_check.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="5dp"
android:layout_weight="1"
android:textSize="24sp" />
<CheckBox
android:id="@+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:clickable="false"
android:focusable="false" />
</LinearLayout>

----------------------------------------------------------------------
アクティビティクラス
CustomCheckListActivity.java
package jp.inujirushi.sample.activity.custom;

import java.util.ArrayList;
import java.util.List;

import jp.inujirushi.sample.R;
import jp.inujirushi.sample.adapter.CustomCheckAdapter;
import jp.inujirushi.sample.adapter.CustomCheckData;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.Toast;

public class CustomCheckListActivity extends Activity implements
OnItemClickListener {
/** アダプタ */
private CustomCheckAdapter mAdapter;

/**
* アクティビティが生成されたときに呼ばれます
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sample_listview);

// リストビューに表示する項目を生成する
List list = new ArrayList();
for (int i = 0; i < 20; i++) {
list.add(new CustomCheckData("項目" + i, true));
}

// リストビューを取得する
ListView listView = (ListView) findViewById(R.id.listView);

// リストビューにカスタムしたリストアダプタを設定する
mAdapter = new CustomCheckAdapter(this, list);
listView.setAdapter(mAdapter);

// リストビューに項目クリックイベントを設定する
listView.setOnItemClickListener(this);
}

/**
* 項目をクリックしたときに呼ばれます
*/
@Override
public void onItemClick(AdapterView parent, View view, int position,
long id) {
// 項目のチェックボックスを取得する
CheckBox chk = (CheckBox) view.findViewById(R.id.checkBox);

// チェックボックスを反転する(アダプタの onCheckedChanged() が呼ばれる)
chk.setChecked(!chk.isChecked());

// 項目情報を取得する
CustomCheckData data = mAdapter.getItem(position);

// 取得した情報をトースト表示する
Toast.makeText(this, position + ":" + data.isChecked,
Toast.LENGTH_SHORT).show();
}
}

スポンサーサイト



ListViewに編集可能なViewを追加する

カスタマイズした ListView に編集可能なView (EditText や CheckBox 等) を追加する場合には、変更した値をどこかに保持する処理が必要になります。
これは以前、ListView をカスタマイズするで書いたように ListView の項目は再利用されているため値を毎回詰め替える必要があるためです。
さて、変更した値を保持する処理ですが、アダプタクラス内の getView() にて項目毎にイベントを設定することで対応します。

今回の記事では CheckBox を例としてサンプルソースを載せました。

参考サイト:mumoshu.log - [android]ListView + CheckBoxでチェック可能なリストを作るときの注意点

注意しないといけないのはイベントを設定するタイミング。
2回目以降(convertView != null)は項目が使いまわされているため、CheckBoxに設定されているイベントは再利用前の行のイベントが設定されています。

なお、変更した値を外(Activity)で取得するには、CustomCheckAdapter#getItem(int postion) を使います。

----------------------------------------------------------------------
リストの項目のレイアウト
res/layout/sample_row_check.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="5dp"
android:layout_weight="1"
android:textSize="24sp" />
<CheckBox
android:id="@+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp" />
</LinearLayout>

----------------------------------------------------------------------
項目のデータクラス
外部から情報を取得できるようにpublic変数にしています
getter/setter 作るのが面倒だったので直接取得するようにしている
CustomCheckData.java
package jp.inujirushi.sample.adapter;

/**
* アダプタに設定するデータ
*/
public class CustomCheckData {
/** 文字列 */
public String text;
/** チェック状態 */
public boolean isChecked;

/**
* コンストラクタ
*
* @param text
* 文字列
* @param isChecked
* チェック状態
*/
public CustomCheckData(String text, boolean isChecked) {
this.text = text;
this.isChecked = isChecked;
}
}

----------------------------------------------------------------------
アダプタクラス
CustomCheckAdapter.java
package jp.inujirushi.sample.adapter;

import java.util.List;

import jp.inujirushi.sample.R;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;

public class CustomCheckAdapter extends ArrayAdapter {

LayoutInflater mInflater;

/**
* コンストラクタ
*
* @param context
* コンテキスト
* @param objects
* 行データ
*/
public CustomCheckAdapter(Context context, List objects) {
// 親のコンストラクタを呼び出す
super(context, 0, objects);

// インフレーターを取得する
this.mInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// ホルダークラスを定義する
ViewHolder holder;

// ビューを設定する
if (convertView == null) {
// ビューに定義したレイアウトをインフレートする
convertView = this.mInflater.inflate(R.layout.sample_row_check,
parent, false);

// ホルダークラスを生成する
holder = new ViewHolder();

// ホルダークラスにレイアウト内のビューを設定する
holder.textView = (TextView) convertView
.findViewById(R.id.textView);
holder.checkBox = (CheckBox) convertView
.findViewById(R.id.checkBox);

// タグにホルダークラスを設定する
convertView.setTag(holder);
} else {
// タグからホルダークラスを取得する
holder = (ViewHolder) convertView.getTag();
}

// 指定された位置のアイテムを取得する
// ※final化してイベント内からも参照できるようにする
final CustomCheckData data = getItem(position);

// ホルダークラスのビューの値を設定する
holder.textView.setText(data.text);

// チェックボックスに変更イベントを設定する
CheckBox chk = holder.checkBox;
chk.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// チェック状態を設定する
data.isChecked = isChecked;
}
});

// イベント設定後にチェックを入れる
// ※イベントより前に設定すると別の行の値が書き換えられてしまう
holder.checkBox.setChecked(data.isChecked);

// 表示するビューを返す
return convertView;
}

/**
* ホルダクラス
*/
class ViewHolder {
/** テキストビュー */
TextView textView;
/** チェックボックス */
CheckBox checkBox;
}
}
※71行目でホルダクラスのチェックボックスを CheckBox クラスに置き換えているのはソース整形時(Ctrl+Shift+F)に崩れてしまうためにやっているだけなので気にしないでね
プロフィール

とむ・やむくん

Author:とむ・やむくん
管理人について

Windows 7 / 64bit
Eclipse 4.2 Juno (日本語パッチ済)

スポンサーサイト
最新トラックバック
検索フォーム
ブロとも申請フォーム
QRコード
QR
Twitter
2013/01/04 19:00 カウント開始