Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Changing visibility on menu items with changing fragment

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

like image 634
modebm Avatar asked Jan 18 '13 21:01

modebm


People also ask

How do we hide the menu on toolbar in one fragment?

How do we hide the menu on toolbar in one fragment? When you click the show button to open a fragment, you can see the fragment menu items ordered before activity menu items. This is because of the menu item's android:orderInCategory attribute value. When you click the hide button to hide the fragment.

How do I change the view of a fragment?

You can use Fragment. getView() . This returns the view of the container which contains the Fragment . On that view, you can call removeAllViews .

How can I change fragments in android?

Use replace() to replace an existing fragment in a container with an instance of a new fragment class that you provide. Calling replace() is equivalent to calling remove() with a fragment in a container and adding a new fragment to that same container. transaction. commit();

How can I tell if an android fragment is destroyed?

Since all fragments are destroyed if the activity is destroyed, a simple answer could be calling getActivity(). isDestroyed() returning true if the activity is destroyed, therefore the fragment is destroyed.


2 Answers

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

like image 88
Eleazer Toluan Avatar answered Oct 06 '22 18:10

Eleazer Toluan


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

May be yes :).

  • In your fragment onCreate, add this :

    setHasOptionsMenu (true);

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.

  • Override onPrepareOptionMenu method in your fragment class.

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

like image 42
S.Thiongane Avatar answered Oct 06 '22 16:10

S.Thiongane