這個CheckableSimpleAdapter是伸廷 SimpleAdapter 的一個類,自帶一個 OnCheckedStateChangeListener 介面,只要 Layout 中帶有 CheckBox 並且在建立 CheckableSimpleAdapter 時表示那個 Resource ID 是用作 Row Select 便可以。
要注意 data 這個 List,每列的 Map 裡會被加進一個 Key-value pair 值,用以表示這一行被選取的狀態。
代碼如下:
/**
* An extended SimpleAdapter for handling Checkable row/item.
*
* Note that extra entity of checked state will be saved to each row data (i.e.
* in each Map object). The key value is {@link#KEY_ROW_SEL_CHECKBOX}
*
* TODO: Isolate the checked state to separated storage but keep the data
* synchronized.
*
* http://www.badbuta.com
*
* @author David Hon
*
*/
public class CheckableSimpleAdapter extends SimpleAdapter implements
OnClickListener {
private final static String LOG_TAG = CheckableSimpleAdapter.class
.getSimpleName();
public final static String KEY_ROW_SEL_CHECKBOX = "_rowSelectCbox";
private final int rowSelCheckBoxResource;
// Backup the list
private final List<? extends Map<String, ?>> data;
private OnCheckedStateChangeListener onCheckedStateChangeListener = null;
/**
* Interface definition for a callback to be invoked when this Checkable
* item state is changed.
*
* @author David Hon
*
*/
public interface OnCheckedStateChangeListener {
/**
* Called when the checkable item check state is changed.
*
* @param position
* the changed item position
* @param checkedState
* a state presents the checkable item
*/
public void onCheckableStateChange(int position, boolean checkedState);
}
/**
* The constructor, which is similar to SimpleAdapter constructor. However
* it requires additional resource id for the CheckBox for row selection.
* Note that there is no checking for invalid CheckBox ID. Please make sure
* given ID is valid. Otherwise getView() may throw NullPointerException
* during runtime.
*
*
* @param context
* @param data
* @param resource
* @param from
* @param to
* @param rowSelCheckBoxResource
* Additional resource id for the CheckBox for row selection.
*/
public CheckableSimpleAdapter(Context context,
List<? extends Map<String, ?>> data, int resource, String[] from,
int[] to, int rowSelCheckBoxResource) {
super(context, data, resource, from, to);
this.rowSelCheckBoxResource = rowSelCheckBoxResource;
this.data = data;
}
/**
* Clear all checked rows (UI and Data)
*/
@SuppressWarnings("unchecked")
public void clearCheckedRows() {
int rowCount = getCount();
for (int i = 0; i < rowCount; i++) {
Map<String, Object> o = (Map<String, Object>) data.get(i);
if (o.containsKey(KEY_ROW_SEL_CHECKBOX)) {
o.put(KEY_ROW_SEL_CHECKBOX, Boolean.FALSE);
}
}
notifyDataSetChanged();
}
/**
* Check if there is ANY checked data
*
* @return
*/
public boolean hasCheckedData() {
int rowCount = getCount();
for (int i = 0; i < rowCount; i++) {
Map<String, ?> o = data.get(i);
if (o.containsKey(KEY_ROW_SEL_CHECKBOX)) {
boolean val = (Boolean) o.get(KEY_ROW_SEL_CHECKBOX);
if (val) {
return true;
}
}
}
return false;
}
/**
* Get the (un)checked row data
*
* @param invertSelection
* FALSE for checked data, TRUE for unchecked data
* @return A List which store the result.
*/
public List<Map<String, ?>> getCheckedData(boolean invertSelection) {
int rowCount = getCount();
List<Map<String, ?>> result = new ArrayList<Map<String, ?>>(rowCount);
for (int i = 0; i < rowCount; i++) {
Map<String, ?> o = data.get(i);
if (o.containsKey(KEY_ROW_SEL_CHECKBOX)) {
boolean val = (Boolean) o.get(KEY_ROW_SEL_CHECKBOX);
if (val != invertSelection) {
result.add(o);
}
}
}
return result;
}
/**
* Get the checked state which stored in the data
*
* @return SparseBooleanArray which store the result.
*/
public SparseBooleanArray getCheckedStates() {
int rowCount = getCount();
SparseBooleanArray result = new SparseBooleanArray();
for (int i = 0; i < rowCount; i++) {
Map<String, ?> o = data.get(i);
// If the check value has not yet set, it should be unchecked
// (unseen), so return the value as FALSE
boolean val = (o.containsKey(KEY_ROW_SEL_CHECKBOX)) ? (Boolean) o
.get(KEY_ROW_SEL_CHECKBOX) : false;
result.append(i, val);
}
return result;
}
/**
* Setterfor OnCheckedStateChangeListener
*
* @param listener
* the OnCheckedStateChangeListener
*/
public void setOnCheckedStateChangeListener(
OnCheckedStateChangeListener listener) {
this.onCheckedStateChangeListener = listener;
}
/*
* (non-Javadoc)
*
* @see android.widget.SimpleAdapter#getView(int, android.view.View,
* android.view.ViewGroup)
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Save the convertView state before creation from super class.
boolean emptyConvertView = (convertView == null);
View v = super.getView(position, convertView, parent);
// expected the returned view should not be null.
// No null-checking, Checkbox may be come from recycle pool.
CheckBox cb = (CheckBox) v.findViewById(rowSelCheckBoxResource);
// Save the position to tag anyway.
cb.setTag(position);
// Create the OnClickListener and set it as necessary.
// i.e. Avoid re-creation of OnClickListener, save resources.
if (emptyConvertView) {
cb.setOnClickListener(this);
}
@SuppressWarnings("unchecked")
Map<String, Object> o = (Map<String, Object>) getItem(position);
if (!o.containsKey(KEY_ROW_SEL_CHECKBOX)) {
// Create key-value for row selection state if it has not yet
// created. (Lazy creation)
o.put(KEY_ROW_SEL_CHECKBOX, Boolean.FALSE);
}
// Get the row selection from data
boolean bVal = (Boolean) o.get(KEY_ROW_SEL_CHECKBOX);
// Set the checkbox check state according to that value:
if (cb.isChecked() != bVal) {
cb.setChecked(bVal);
}
// Done!
return v;
}
/*
* (non-Javadoc)
*
* @see android.view.View.OnClickListener#onClick(android.view.View)
*/
@Override
public void onClick(View v) {
if (v instanceof CheckBox) {
// It should be a Checkbox
CheckBox cb = (CheckBox) v;
// Retrieve the data position from tag:
Object tag = cb.getTag();
if (tag != null && (tag instanceof Integer)) {
int pos = (Integer) cb.getTag();
@SuppressWarnings("unchecked")
Map<String, Object> o = (Map<String, Object>) data.get(pos);
boolean cbIsChecked = cb.isChecked();
// Save the checkbox check state (i.e. row
// selection) to data:
o.put(KEY_ROW_SEL_CHECKBOX, Boolean.valueOf(cbIsChecked));
// notify the state changed.
if (onCheckedStateChangeListener != null) {
onCheckedStateChangeListener.onCheckableStateChange(pos,
cbIsChecked);
}
} else {
// It should be programming error, anyway log it.
Log.e(LOG_TAG, "CheckBox tag for data position is invalid!");
}
}
}
}
NOTE: imports, package 說自己加回去吧
沒有留言:
發佈留言