简体   繁体   中英

How to refresh ActionBar navigation item during traversing the Fragment back stack?

The Android 4.1 ActionBar provides a useful navigation mode as a list or tab. I am using a SpinnerAdapter to select from three fragments to be displayed in view android.R.id.content . The onNavigationItemSelected() listener then inflates each fragment to the view and adds it to the back stack using FragmentTransaction.addToBackStack(null) .

This all works as advertised, but I don't know how to update the ActionBar to reflect the current back stack. Using the ActionBar.setSelectedNavigationItem(position) works but also triggers a new OnNavigationListener() which also creates another FragmentTransaction (not the effect I want). The code is shown below for clarification. Any help with a solution is appreciated.


public class CalcActivity extends Activity {
private String[] mTag = {"calc", "timer", "usage"};
private ActionBar actionBar;

/** An array of strings to populate dropdown list */
String[] actions = new String[] {
    "Calculator",
    "Timer",
    "Usage"
};

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    this.actionBar = getActionBar();

    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
    // may not have room for Title in actionbar
    actionBar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);

    actionBar.setListNavigationCallbacks(
    // Specify a SpinnerAdapter to populate the dropdown list.
    new ArrayAdapter<String>(
        actionBar.getThemedContext(),
        android.R.layout.simple_list_item_1,
        android.R.id.text1,
        actions),
    // Provide a listener to be called when an item is selected.
    new NavigationListener()
    );      
}

public class NavigationListener implements ActionBar.OnNavigationListener {
    private Fragment mFragment;
    private int firstTime = 0;

    public boolean onNavigationItemSelected(int itemPos, long itemId) {
        mFragment = getFragmentManager().findFragmentByTag(mTag[itemPos]);

        if (mFragment == null) {
            switch (itemPos) {
            case 0:
                mFragment = new CalcFragment();
                break;
            case 1:
                mFragment = new TimerFragment();
                break;
            case 2:
                mFragment = new UsageFragment();
                break;
            default:
                return false;
            }               
            mFragment.setRetainInstance(true);
        }

        FragmentTransaction ft = getFragmentManager().beginTransaction();
        if (firstTime == 0) {
            firstTime++;
            ft.add(android.R.id.content, mFragment, mTag[itemPos]);
        } else {
            ft.replace(android.R.id.content, mFragment, mTag[itemPos]);
            ft.addToBackStack(null);
        }
        ft.commit();

        Toast.makeText(getBaseContext(), "You selected : " + 
                actions[itemPos], Toast.LENGTH_SHORT).show();

        return true;
    }       
}

public static class CalcFragment extends Fragment {             
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_calc, container, false);
    return v;
    }   
}

public static class TimerFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_timer, container, false);
    return v;
    }   
}

public static class UsageFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_usage, container, false);
    return v;
    }
}

You could do something like this:

  1. Create a boolean to track when you are selecting a navigation item based on the back button:

     private boolean mListIsNavigatingBack = false; 
  2. Override onBackPressed, in the override, check if the backstack has items, if so handle yourself, if not call the superclass:

     public void onBackPressed() { if(getFragmentManager().getBackStackEntryCount() > 0){ mListIsNavigatingBack = true; //You need to get the previous index in the backstack through some means //possibly by storing it in a stack int previousNavigationItem = ???; getActionBar().setSelectedNavigationItem(previousNavigationItem); } else{ super.onBackPressed(); } } 
  3. Inside NavigationListener, handle the mListIsNavigatingBack state, manually pop the back stack and unset the state:

     if(mListIsNavigatingBack){ if(fm.getBackStackEntryCount() > 0){ fm.popBackStack(); } mListIsNavigatingBack = false; } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM