5

ho implementato una barra di modalità di azione contestuale in una soluzione annidata. Questo frammento fa parte di un visualizzatore di viste e il pager di visualizzazione è anche un frammento e parte di un cassetto di navigazione.modalità di azione contestuale in frammento - chiudi se non è a fuoco?

Il mio problema: voglio chiudere la barra della modalità di azione contestuale se il frammento non è più focalizzato. Quindi, se sfoglio il pager della vista, la barra della modalità di azione dovrebbe chiudersi. Ma se utilizzo il metodo onPause() del frammento nidificato, il metodo non viene chiamato direttamente. Spesso si aspetta fino a quando ho strisciato due o tre volte in avanti ... Ecco alcune foto:

enter image description here

enter image description here

Nella seconda foto si può vedere che la barra di modalità di azione è ancora lì. Quindi la mia domanda è: In quale metodo dovrei chiamare il mio metodo actionModeBar.finish(), per chiudere direttamente la barra della modalità di azione se lascio il frammento?

Forse il codice del frammento che si aiuta:

public class EditorFragment extends Fragment { 

    private static final String KEY_POSITION="position"; 
    ListView listView; 
    private boolean isMultipleList = false; 
    private ActionMode acMode; 
    private int counterChecked = 0; 

    private ActionMode.Callback modeCallBack = new ActionMode.Callback() { 

    public boolean onPrepareActionMode(ActionMode mode, Menu menu){ 
      return false; 
     } 

     public void onDestroyActionMode(ActionMode mode) { 
      listView.clearChoices(); 
      for (int i = 0; i < listView.getChildCount(); i++) 
       listView.setItemChecked(i, false); 
       listView.post(new Runnable() { 
        @Override 
        public void run() { 
         listView.setChoiceMode(ListView.CHOICE_MODE_NONE); 
        } 
       }); 
      isMultipleList = false; 
      counterChecked = 0; 
      mode = null; 
     } 

     public boolean onCreateActionMode(ActionMode mode, Menu menu) { 
      mode.setTitle("1 Aufgabe"); 
      mode.getMenuInflater().inflate(R.menu.actionmode, menu); 
      return true; 
     } 

     public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 
      switch (item.getItemId()) { 
      case R.id.actionmode_delete: 
       int choiceCount = listView.getCount(); 
       SparseBooleanArray spBoolArray = listView.getCheckedItemPositions(); 

       DBAufgaben db = new DBAufgaben(MainActivity.getMContext()); 
       db.open(); 

       for (int i = 0; i < choiceCount; i++) { 
        if(spBoolArray.get(i)){ 
         db.deletContact(listView.getItemIdAtPosition(i)); 
        } 

       } 
       Cursor cursor = db.getAllRecords(); 
       AdapterEingang adapterE = new AdapterEingang(MainActivity.getMContext(), cursor, 0); 
       listView.setAdapter(adapterE); 
       db.close(); 
       mode.finish(); 
       break; 
      case R.id.actionmode_cancel: 
       mode.finish(); 
       break; 
      } 
      return false; 
     } 
    }; 

    //......// 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 

     View rootView = null; 
     int position = getArguments().getInt(KEY_POSITION, -1); 

     switch(position){ 
     case 0: 
      rootView = inflater.inflate(R.layout.pager_list, null); 
      listView = (ListView) rootView.findViewById(R.id.pager_list); 

      Context context = MainActivity.getMContext(); 

      DBAufgaben db = new DBAufgaben(context); 

      db.open(); 
      Cursor cursor = db.getAllRecords(); 
      AdapterEingang adapterE = new AdapterEingang(context, cursor, 0); 
      listView.setAdapter(adapterE); 
      db.close(); 

      listView.setOnItemLongClickListener(new OnItemLongClickListener(){ 



       @Override 
       public boolean onItemLongClick(AdapterView<?> adapterView, View view, 
         int position, long id) { 
        if(!isMultipleList){ 
         acMode = MainActivity.getInstance().startActionMode(modeCallBack); 
         listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); 
         listView.setItemChecked(position, true); 
         isMultipleList = true; 
         counterChecked++; 
         setNewTitle();      
        } else { 
         listView.setItemChecked(position, true); 
         counterChecked++; 
         setNewTitle(); 
        } 

        return true; 
       } 

       }); 
      listView.setOnItemClickListener(new OnItemClickListener(){ 

      @Override 
      public void onItemClick(AdapterView<?> adapterView, View view, int position, 
        long id) { 
       Log.d(getTag(), "Datensatz: "+String.valueOf(id)); 
       if(isMultipleList){ 
        if(listView.isItemChecked(position)){ 
         listView.setItemChecked(position, true); 
         counterChecked++; 
         setNewTitle(); 
        } else { 
         listView.setItemChecked(position, false); 
         counterChecked--; 
         setNewTitle(); 
        } 

       } 

      } 

      }); 
      break; 
     default: 
      rootView = inflater.inflate(R.layout.frag_dummy, null); 
      TextView txt = (TextView) rootView.findViewById(R.id.dummy_txt); 
      txt.setText(String.valueOf(position)); 
      break; 
     } 



     return(rootView); 
    } 
    public void setNewTitle(){ 
     if(counterChecked == 1){ 
      acMode.setTitle(counterChecked+" Aufgabe"); 
     } else { 
      acMode.setTitle(counterChecked+" Aufgaben"); 
     } 
    } 
    @Override 
    public void onPause(){ 
     super.onPause(); 
     if(isMultipleList){ 
      acMode.finish(); 
     } 
    } 
} 

risposta

5

ViewPagers tenere più pagine attive in qualsiasi momento (per impostazione predefinita, la pagina prima e pagina dopo pagina attualmente visualizzata), quindi, perché onPause() non viene chiamato finché non si sfogliano due pagine.

La cosa migliore sarebbe quella di utilizzare un ViewPager.OnPageChangeListener, e mostrare e nascondere l'ActionMode in onPageSelected(..) (vale a dire se la pagina selezionata non è quella con l'ActionMode, nascondere l'ActionMode). Probabilmente dovrai implementarlo nell'attività che ospita il tuo ViewPager.

4

questo ha funzionato per me:

@Override 
public void setUserVisibleHint(boolean isVisibleToUser) { 
    if (!isVisibleToUser && this.listView != null) { 
     //HACK this is done in order to finish the contextual action bar 
     int choiceMode = this.listView.getChoiceMode(); 
     this.listView.setChoiceMode(choiceMode); 
    } 
} 
+2

Quella sporca HACK ed è sporca è esattamente quello che mi serviva. Grazie. Avevo già provato a chiamare semplicemente Finish sull'actionMode precedentemente memorizzato –

3

ho unito il codice dalla OP con la forzatura suggerita da pomber utente:

  • risparmio il ActionMode ad un campo di classe quando si crea la modalità di azione .
  • Ho impostato il campo su null quando la modalità di azione è stata distrutta.
  • Escludo setUserVisibleHint nel mio frammento e chiamo ActionMode#finish() se il frammento non è visibile nel pager della vista.
  • Io chiamo anche ActionMode#finish() nel metodo onPause() del frammento per chiudere il frammento se l'utente naviga altrove.

Codice:

@Nullable 
ActionMode mActionMode = null; 

@Override 
public void onActivityCreated(Bundle savedInstanceState) { 
    super.onActivityCreated(savedInstanceState); 

    // Start out with a progress indicator. 
    setListShownNoAnimation(false); 

    setEmptyText(getText(R.string.no_forms_in_progress)); 

    getListView().setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE_MODAL); 
    getListView().setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() { 
     @Override 
     public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { 
      // Here you can do something when items are selected/de-selected, 
      // such as update the title in the CAB 
     } 

     @Override 
     public boolean onCreateActionMode(ActionMode mode, Menu menu) { 
      MenuInflater inflater = mode.getMenuInflater(); 
      inflater.inflate(R.menu.context_saved_item, menu); 
      inflater.inflate(R.menu.context_instance_list, menu); 
      mActionMode = mode; 
      return true; 
     } 

     @Override 
     public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 
      return false; 
     } 

     @Override 
     public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 
      switch (item.getItemId()) { 
       case R.id.action_delete: 
        confirmDelete(getListView().getCheckedItemIds()); 
        return true; 
       case R.id.action_print: 
        print(getListView().getCheckedItemIds()); 
        return true; 
      } 
      return false; 
     } 

     @Override 
     public void onDestroyActionMode(ActionMode mode) { 
      mActionMode = null; 
     } 
    }); 
} 

@Override 
public void onPause() { 
    super.onPause(); 
    if (mActionMode != null) { 
     mActionMode.finish(); 
    } 
} 

@Override 
public void setUserVisibleHint(boolean isVisibleToUser) { 
    super.setUserVisibleHint(isVisibleToUser); 
    if (mActionMode != null && !isVisibleToUser) { 
     mActionMode.finish(); 
    } 
} 
3

Ecco cosa ha funzionato per me -

  1. mantenere un riferimento statico per la modalità di azione in MyFragment:

public static ActionMode mActionMode;

@Override 
    public boolean onCreateActionMode(ActionMode mode, Menu menu) { 
     mActionMode = mode; 
     return true; 
    } 

    @Override 
    public void onDestroyActionMode(ActionMode mode) { 
     mActionMode = null; 
    } 
  1. Impostare ViewPager.OnPageChangeListener in MyViewPagerActivity.

mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 
 

 
      .... 
 

 
      @Override 
 
      public void onPageScrollStateChanged(int state) { 
 
       if(MyFragment.mActionMode != null) MyFragment.mActionMode.finish(); 
 
      } 
 

 

 
     });

1

È possibile utilizzare il metodo onDestroyOptionsMenu() all'interno del frammento:

public void onDestroyOptionsMenu() { 
    super.onDestroyOptionsMenu(); 
    if (mActionMode != null) { 
     mActionMode.finish(); 
     mActionMode = null; 
    } 
} 
Problemi correlati