2012-04-20 7 views
8

Mam ListView, który zwykle jest singleChoicechoiceMode. Gdy użytkownik długo naciska na element, chcę wprowadzić tryb działania, który pozwala wybrać wiele elementów, aby umożliwić wykonanie akcji na wybranych elementach.Zmień ListView choiceMode z singleChoice na multipleChoiceModal

Jestem w stanie skonfigurować ListView tak, aby był w trybie singleChoice i użytkownik może wybrać elementy listy, aby wyświetlić fragment szczegółów obok niego i mieć sam element listy wyświetlany w stanie aktywowanym.

Jestem również w stanie skonfigurować ListView tak, że jest w multipleChoiceModalchoiceMode i wykonując długie naciśnięcie elementu uruchamia tryb działania i pozwala wybrać więcej, ale teraz ListView nie pozwoli jeden wybór w normalny tryb (bez trybu akcji).

Jak mogę mieć ListView, który jest w trybie singleChoice, a następnie przejść do trybu multipleChoiceModal, gdy element jest długo naciśnięty?

Jest to najbliżej byłem w stanie wymyślić:

  1. ustawić ListView do trybu singleChoice
  2. ustawić ListView na OnItemLongClickListener iw tym słuchacza:
    1. ustawić ListView na OnItemLongClickListener do null
    2. ustawić ListView na choiceMode do multipleChoiceModal
    3. Zadzwoń pod numer view.performClick() w sprawie elementu, który był długo naciśnięty.

To podejście ma kilka problemów.

  1. Tryb akcji rozpoczyna się dopiero po drugim naciśnięciu przycisku.
  2. Gdy zadzwonię pod numer getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); w onDestroyActionMode, otrzymam java.lang.StackOverflowError, ponieważ ta metoda kończy się również próbą zniszczenia trybu akcji (ale nie mamy jeszcze wróconych z niszczenia).
+0

co powinno nastąpić po wprowadzeniu multipleChoiceMode, wybrane 2 i wrócić do singleCheckMode? – user387184

Odpowiedz

3

użyłem tego w jednym z moich programów

nam ListView.CHOICE_MODE_MULTIPLE_MODAL następnie 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); 
     } 
    } 

} 

ten pozwala na pojedynczy wybór pojedynczy listview kliknięcia i długie kliknięcie wielokrotnego wyboru. To wszystko zostało zaczerpnięte z aplikacji do wysyłania wiadomości ICS, więc możesz to przeglądać.

+0

Być może brakuje mi czegoś, ale w jaki sposób lista przechodzi w tryb singleChoiceMode po zniszczeniu trybu działania? –

+0

wystarczy przesłonić 'onListItemClick' w liście, a następnie, gdy użytkownik kliknie element w widoku listy, pokazuje fragment odnoszący się do kliknięcia. chyba że czegoś tu brakuje? – tyczj

+0

Myślę, że część, o której nie wspomniałem, to to, że moje elementy listy korzystają z funkcji state_activated. state_activated only jest ustawione na true, gdy element jest faktycznie wybrany jako wybór w trybie singleChoice, więc naprawdę chcę, aby mój ListView przeszedł z powrotem do trybu singleChoice. –

5

Naprawdę wydawało się, że jest to awkard dla tego przełącznika trybu wyboru, ponieważ nie ma czystego i prostego rozwiązania, które mógłbym google. HFM (wiarę człowieka) oraz KISS (keep it simple stupid) pomogło;)

1.Start w trybie pojedynczego wyboru i ustawić wszystkie słuchaczy (odbywa się to gdzie ustawić adapter listy)

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

2.implementuj interfejsy, aby przełączać się między trybami wyboru. TRICK, aby to działało, to przełączenie z powrotem do trybu pojedynczego wyboru poza implementacją, czyli PO zniszczeniu trybu akcji !! Więc po prostu użyj prostej flagi do oznaczenia zniszczenia CAB. Innym TRICK jest zwrócenie false onItemLongClick, aby tryb wyboru miał czas na wprowadzenie w życie.

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 jest przełącznik z powrotem

@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); 

    } 
+0

Przepraszam za przywrócenie starego posta, ale wypróbowałem sposób opisany powyżej, ale moje elementy listy nie są podświetlone na niebiesko (jak na Whatsapp). Jak mogę to zrobić? Dzięki ! – Leonardo

+0

Jeśli interfejs użytkownika wymaga nawigacji i powrotu z powrotem przez odtwarzanie (na przykład, gdy interfejs użytkownika oparty na fragmencie), nie zapomnij przełączyć stanu ListView na 'ListView.CHOICE_MODE_SINGLE', jeśli był w' ListView.CHOICE_MODE_MULTIPLE_MODAL' w momencie odejścia. Ponadto, należy pozostawić przełączanie drenażu z MULTI na SINGLE. Robię to tak: if (! IsCABDestroyed) { \t int selection = contentList.getCheckedItemPositions(). KeyAt (0); \t contentList.setChoiceMode (ListView.CHOICE_MODE_SINGLE); \t contentList.setItemChecked (wybór, prawda); } // odsuń nawigację – StAlex