Change ListView choiceMode from singleChoice to multipleChoiceModal

I have a ListView, which is usually a singleChoice choiceMode . When the user takes a long time to click on an item, I want to enter an action mode that allows me to select multiple items so that they can perform an action for any selected items.

I can configure the ListView to be in singleChoice mode, and the user can select the list items to display a fragment of the details next to it, and the list item itself is shown in its activated state.

I can also configure the ListView to be in multipleChoiceModal choiceMode and a long press on the item launches the action mode and allows several choices, but now the ListView does not allow single selection in normal mode (without action).

How can I get a ListView in singleChoice mode and then put it in multipleChoiceModal mode when the item is long pressed?

This is the closest I could come up with:

  • set ListView mode to singleChoice
  • set ListView OnItemLongClickListener in this listener OnItemLongClickListener :
    • set ListView OnItemLongClickListener to null
    • set ListView choiceMode to multipleChoiceModal
    • call view.performClick() on the element that has been pressed long.

This approach has a couple of problems.

  • The action mode does not start until the second time, when I long click on the item.
  • When I call getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); in onDestroyActionMode , I get java.lang.StackOverflowError because this method also tries to destroy the action mode as well (but we have not returned from the destruction yet).
+8
android android-3.0-honeycomb
source share
2 answers

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 you to select one single click and click several times. All this has been extracted from the ICS messaging app so you can view it too

+3
source share

Actually, it looked uncomfortable because there is no clean and simple solution that I could make Google. HFM (there is a man of faith) and KISS (keep it just stupid) helped;)

1.start in single select mode and install all listeners (this is done where you install the list adapter)

 listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); listView.setOnItemLongClickListener(liListener); listView.setMultiChoiceModeListener(mcListener); 

2.Use the interfaces to switch between selection modes. TRICK, to make it work, is to return to single-choice mode outside the implementation, that is, AFTER you destroy the action mode! So just use a simple flag to mark the destruction of the CAB. Another TRICK must return false onItemLongClick for the selection mode to take 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 come 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); } 
+5
source share

All Articles