I have a ListView that normally is the singleChoice
choiceMode
. When the user long presses on an item, I want to enter an action mode that allows selecting multiple items so they can perform an action on any selected items.
I am able to configure the ListView
so that it is in singleChoice
mode and the user is able to select list items to display a details fragment next to it and have the list item itself shown in its activated state.
I am also able to configure the ListView
so that it is in the multipleChoiceModal
choiceMode
and performing a long press on an item starts the action mode and allows multiple selections, but now the ListView will not allow a single selection in the normal mode (no action mode).
How can I have a ListView that is in singleChoice
mode and then transition it to multipleChoiceModal
mode when an item is long pressed?
This is the closest I've been able to come up with:
singleChoice
modeOnItemLongClickListener
and in that listener:
OnItemLongClickListener
to null
choiceMode
to multipleChoiceModal
view.performClick()
on the item that was long pressed.This approach has a couple problems.
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
in onDestroyActionMode
I get a java.lang.StackOverflowError
because that method ends up trying to destroy the action mode as well (but we have no yet returned from the destroy).It really seemed awkard this choice mode switch since there is no clean and simple solution I could google. HFM (have faith man) and KISS (keep it simple stupid) helped ;)
1.start in single mode choice and set all the listeners (this is done where you set the list adapter)
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
listView.setOnItemLongClickListener(liListener);
listView.setMultiChoiceModeListener(mcListener);
2.implement the interfaces to switch between choice modes. The TRICK to make it work is to switch back to single choice mode outside the implementation, meaning AFTER you destroy the action mode!! So just use a simple flag to mark the CAB destruction. Another TRICK is to return false onItemLongClick so that the the choice mode have time to get into effect.
private OnItemLongClickListener liListener = new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
isCABDestroyed = false;
return false; // so this action does not consume the event!!!
}
};
private MultiChoiceModeListener mcListener = new MultiChoiceModeListener() {
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
final int checkedCount = listView.getCheckedItemCount();
switch (checkedCount) {
case 0:
mode.setSubtitle(null);
break;
case 1:
mode.setSubtitle("One item selected");
break;
default:
mode.setSubtitle("" + checkedCount + " items selected");
break;
}
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.delete:
//do your action command here
mode.finish();
return true;
default:
return false;
}
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
return true;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
isCABDestroyed = true; // mark readiness to switch back to SINGLE CHOICE after the CABis destroyed
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
};
3.Here is the switch back
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
if(isCABDestroyed) {
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
//do your action command here
}
l.setItemChecked(position, true);
}
I used this in one of my programs
us the ListView.CHOICE_MODE_MULTIPLE_MODAL
then lv.setMultiChoiceModeListener(new ModeCallBack());
public class ModeCallBack implements ListView.MultiChoiceModeListener{
View mSelectView;
TextView mSelectedCount;
ArrayList<Long> mCheckedItems;
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getActivity());
SharedPreferences.Editor edit = pref.edit();
if(item.getItemId() == R.id.bowler_delete){
for(int i=0; i<mCheckedItems.size(); i++){
long id = mCheckedItems.get(i);
getActivity().getContentResolver().delete(BowlersDB.CONTENT_URI,BowlersDB.ID+"="+id,null);
}
}else if(item.getItemId() == R.id.bowler_add_ball){
if(mCheckedItems.size() > 1){
Toast.makeText(getActivity(),"Can only add bowling balls to one bowler at a time",Toast.LENGTH_SHORT).show();
}else{
edit.putLong(Preferences.BOWLER_SELECTED_FOR_BALL,mCheckedItems.get(0)).commit();
ListFragment lf = new ManufacturersList();
FragmentTransaction ft;
ft = getFragmentManager().beginTransaction();
ft.replace(R.id.frameOne, lf).addToBackStack(null).commit();
//mRemover.rFragment();
}
}else if(item.getItemId() == R.id.add_bowler_to_team){
for(int i=0; i<mCheckedItems.size(); i++){
long id = mCheckedItems.get(i);
ContentValues values = new ContentValues();
values.put(TeamBowlers.BOWLER_ID,id);
values.put(TeamBowlers.TEAM_ID,pref.getLong(Preferences.TEAM_SELECTED,1));
getActivity().getContentResolver().insert(TeamBowlers.CONTENT_URI, values);
}
FragmentManager fm = getFragmentManager();
fm.popBackStack();
}
mode.finish();
return true;
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflate = getActivity().getMenuInflater();
if(fromTeam){
inflate.inflate(R.menu.bowlers_team_action_menu, menu);
}else{
inflate.inflate(R.menu.bowler_action_menu, menu);
}
if(mSelectView == null){
mSelectView = (ViewGroup)LayoutInflater.from(getActivity()).inflate(R.layout.select_count_layout,null);
mSelectedCount = (TextView)mSelectView.findViewById(R.id.count_tv);
}
if(mCheckedItems == null){
mCheckedItems = new ArrayList<Long>();
}
mode.setCustomView(mSelectView);
return true;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
mCheckedItems = null;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
if(mSelectView == null){
mSelectView = (ViewGroup)LayoutInflater.from(getActivity()).inflate(R.layout.select_count_layout,null);
mSelectedCount = (TextView)mSelectView.findViewById(R.id.count_tv);
}
if(mCheckedItems == null){
mCheckedItems = new ArrayList<Long>();
}
return true;
}
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position,long id, boolean checked) {
final int count = lv.getCheckedItemCount();
mSelectedCount.setText(String.valueOf(count));
if(checked){
mCheckedItems.add(id);
}else{
mCheckedItems.remove(id);
}
}
}
this allows for single choice single listview click and long click multiple selection. This was all pulled from the ICS messaging app so you can browse that too
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With