這個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 說自己加回去吧
沒有留言:
發佈留言