This will work in SDK 7 (android 2.1) and higher. (together with SherlockActionBar)
Totaly mimic gmail listbox experience.
I override onTouchEvent so press in the left corner side will activate selection mode;
mutch better then trying to click on the tiny cheackbox.
I override performItemClick so pressing not in the left will act as a Regular press action.
I override setItemChecked so it will update mActionMode as needed.
public class SelectListView extends ListView {
private SherlockFragmentActivity mActivity;
ActionMode mActionMode;
public SelectListView(Context context) {
this( context, null, 0);
}
public SelectListView(Context context, AttributeSet attrs) {
this( context, attrs, 0);
}
public SelectListView(Context context, AttributeSet attrs, int defStyle) {
super( context, attrs, defStyle );
setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
mActivity = (SherlockFragmentActivity) context;
}
@Override
public boolean performItemClick(View view, int position, long id) {
OnItemClickListener mOnItemClickListener = getOnItemClickListener();
if (mOnItemClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
if (view != null)
view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
mOnItemClickListener.onItemClick(this, view, position, id);
return true;
}
return false;
}
boolean mSelectionMode = false;
int mStartPosition;
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
final int x = (int) ev.getX();
final int y = (int) ev.getY();
if (action == MotionEvent.ACTION_DOWN && x < getWidth() / 7) {
mSelectionMode = true;
mStartPosition = pointToPosition(x, y);
}
if (!mSelectionMode)
return super.onTouchEvent(ev);
switch (action) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
if (pointToPosition(x, y) != mStartPosition)
mSelectionMode = false;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
default:
mSelectionMode = false;
int mItemPosition = pointToPosition(x, y);
if (mStartPosition != ListView.INVALID_POSITION)
setItemChecked(mItemPosition, !isItemChecked(mItemPosition));
}
return true;
}
@Override
public void setItemChecked(int position, boolean value) {
super.setItemChecked(position, value);
// boolean r = getAdapter().hasStableIds();
int checkedCount = getCheckItemIds().length;
if (checkedCount == 0) {
if (mActionMode != null)
mActionMode.finish();
return;
}
if (mActionMode == null)
mActionMode = mActivity.startActionMode(new ModeCallback());
mActionMode.setTitle(checkedCount + " selected");
}
class ModeCallback implements ActionMode.Callback {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
menu.add(getResources().getString(R.string.aBar_remove)).setIcon(R.drawable.ic_action_trash)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
Toast.makeText(mActivity, "Delted items", Toast.LENGTH_SHORT).show();
mode.finish();
return true;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
clearChecked();
}
}
public void clearChecked() {
SparseBooleanArray CItem = getCheckedItemPositions();
for (int i = 0; i < CItem.size(); i++)
if (CItem.valueAt(i))
super.setItemChecked(CItem.keyAt(i), false);
}
}
you can use any listbox adapter you need.
if you have a checkbox on your list_item_layout tou need to extent your adapter like this:
ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(this, R.layout.simple_list_item_multiple_choice,
R.id.text1, Cheeses.sCheeseStrings) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
CheckBox checkBox = (CheckBox) v.findViewById(R.id.CheckBox);
checkBox.setChecked(((ListView)parent).isItemChecked(position));
return v;
}
};
Don't forget to use android:background="?attr/activatedBackgroundIndicator" on your list_item_layout.xml