9

I want to change the visibility of menu items of a fragment activity (abs) when ever I change the fragment in the activity. The fragments are SherlockListFragments.

The menu items I want to show/hide are spinners I create on menu creation:

public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    MenuInflater inflater = getSupportMenuInflater();

    IcsSpinner herbSortSpinner = new IcsSpinner(this, null, R.attr.actionDropDownStyle);
    SpinnerAdapter herbSortSpinnerAdapter = ArrayAdapter.createFromResource(this, R.array.herb_sort_elements, android.R.layout.simple_spinner_dropdown_item);
    herbSortSpinner.setAdapter(herbSortSpinnerAdapter);
    herbSortSpinner.setOnItemSelectedListener(this);
    herbSortSpinner.setId(HERB_SPINNER_ID);
    menu.add(R.string.menu_sort).setActionView(herbSortSpinner).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

    IcsSpinner noteSortSpinner = new IcsSpinner(this,  null, R.attr.actionDropDownStyle);
    SpinnerAdapter noteSortSpinnerAdapter = ArrayAdapter.createFromResource(this, R.array.note_sort_elements, android.R.layout.simple_spinner_dropdown_item);
    noteSortSpinner.setAdapter(noteSortSpinnerAdapter);
    noteSortSpinner.setOnItemSelectedListener(this);
    noteSortSpinner.setId(NOTE_SPINNER_ID);
    menu.add(R.string.menu_sort).setActionView(noteSortSpinner).setVisible(false).setEnabled(false).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

    inflater.inflate(R.menu.activity_lexicon, menu);
    menuHolder.setMenu(menu);
    return true;
}

My logic for switching the fragments is:

public boolean onNavigationItemSelected(int position, long itemId) {

    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    switch(position) {
    case 0:
        List<Herb> herbList = findHerbsByIntent(getHerbLocale());
        HerbListFragment herbListFragment = new HerbListFragment();
        herbListFragment.setListAdapter(new HerbListAdapter(this, getHerbLocale(), herbList));
        fragmentTransaction.replace(R.id.fragment_container, herbListFragment, HERB_LIST_FRAGMENT_TAG);
        //menuHolder.showHerbsSpinner();
        break;
    case 1:
        SymptomListFragment symptomListFragment = new SymptomListFragment();
        symptomListFragment.setListAdapter(new SymptomListAdapter(this, getDefaultSymptomLocale()));
        fragmentTransaction.replace(R.id.fragment_container, symptomListFragment, SYMPTOM_LIST_FRAGMENT_TAG);
        //menuHolder.showHerbsSpinner();
        break;
    case 2:
        NoteRepository noteRepository = new NoteRepository(this);
        List<Note> notes = noteRepository.getNoticables(ReferedType.HERB);
        NoteListFragment noteListFragment = new NoteListFragment();
        noteListFragment.setListAdapter(new NoteListAdapter(this, getHerbLocale(), notes));
        fragmentTransaction.replace(R.id.fragment_container, noteListFragment, NOTE_LIST_FRAGMENT_TAG);
        //menuHolder.showNotesSpinner();
        break;
    case 3:
        FavoriteRepository favoriteRepository = new FavoriteRepository(this);
        Set<Integer> favoriteHerbs = favoriteRepository.getFavorables(ReferedType.HERB);
        List<Herb> favoriteHerbList = herbRepository.getHerbsByIds(favoriteHerbs, getHerbLocale());
        FavoriteHerbListFragment favoriteHerbListFragment = new FavoriteHerbListFragment();
        favoriteHerbListFragment.setListAdapter(new HerbListAdapter(this, getHerbLocale(), favoriteHerbList));
        fragmentTransaction.replace(R.id.fragment_container, favoriteHerbListFragment, HERB_LIST_FRAGMENT_TAG);
        //menuHolder.showHerbsSpinner();
        break;
    }
    fragmentTransaction.commit();

    return true;
}

My first idea was to hold the menu object in a holder class and manipulate it there whenever I switch the fragment (in every case statement above).

static class MenuHolder {

    private Menu mMenu;

    void setMenu(Menu menu) {
        mMenu = menu;
    }

    void showNotesSpinner() {
        if (mMenu != null) {
            mMenu.findItem(HERB_SPINNER_ID).setVisible(false).setEnabled(false);
            mMenu.findItem(NOTE_SPINNER_ID).setVisible(true).setEnabled(true);
        }
    }

    void showHerbsSpinner() {
        if (mMenu != null) {
            mMenu.findItem(NOTE_SPINNER_ID).setVisible(false).setEnabled(false);            
            mMenu.findItem(HERB_SPINNER_ID).setVisible(true).setEnabled(true);
        }
    }
}

My problem is that there is no menu item with the given ID which are activity local constants. I get an NPE here. Does anybody have an idea how I can fix that? Is there a better way to change the menu on switching fragments?

Best regards Carsten

modebm
  • 121
  • 1
  • 5
  • Helped myself yesterday. I have cleaned up my cluttered code (instanitating the fragments only once in onCreate) and stored the menu items directly into the holder. Now it works like a charm. – modebm Jan 19 '13 at 07:36

2 Answers2

21

Is there a better way to change the menu on switching fragments?

May be yes :).

The doc :

Report that this fragment would like to participate in populating the options menu by receiving a call to onCreateOptionsMenu(Menu, MenuInflater) and related methods.

Prepare the Screen's standard options menu to be displayed. This is called right before the menu is shown, every time it is shown. You can use this method to efficiently enable/disable items or otherwise dynamically modify the contents.

Then, in this method, try to find your menu items by ID, and make them visible/unvisible, enabled/disabled, like this :

@Override
public void onPrepareOptionsMenu(Menu menu) {    
    menu.findItem(HERB_SPINNER_ID).setVisible(false).setEnabled(false);
}

Read More

S.Thiongane
  • 6,883
  • 3
  • 37
  • 52
  • 3
    This answer deserves much more upvotes. However, in a PreferenceFragment, the necessary Override-decleration would be: public void onPrepareOptionsMenu(Menu menu){ /*..*/ } Nevertheless, you saved me a lot of work. Thanks. :) – Daniel Gilbert Oct 09 '14 at 11:45
  • 1
    helped me as well, thanks, and mMenu should be menu, and it should not return anything as it's a void. – fizgig Feb 23 '15 at 19:49
0

In my case, I have 2 fragments that has a different menu item.

On my MainActivity:

FragmentA fragmentA = new FragmentA();
fragmentA.setTargetFragment(fragmentA, 0);
FragmentB fragmentB = new FragmentB();
fragmentB.setTargetFragment(fragmentB, 1);

and FragmentA and FragmentB has:

@Override
public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
    if(hidden) {
        getTargetFragment().setMenuVisibility(false);
    }else{
        getTargetFragment().setMenuVisibility(true);
    }
}

this will let menu from fragment A be visible when B is leaving. If it’s going back from B to A old menus from A can be visible.

Reference: here

Eleazer Toluan
  • 233
  • 4
  • 14