2012-10-17 3 views
6

Das Android 4.1 ActionBar bietet einen nützlichen Navigationsmodus als Liste oder Registerkarte. Ich verwende ein SpinnerAdapter aus drei Fragmenten auszuwählen im Hinblick android.R.id.content angezeigt werden. Der onNavigationItemSelected() Zuhörer aufbläst dann jedes Fragment zu der Ansicht, und fügt sie Stapel zu der Rückseite unter Verwendung von FragmentTransaction.addToBackStack(null).Wie aktualisiere ich das ActionBar-Navigationselement beim Durchqueren des Fragment-Back-Stacks?

Das funktioniert alles wie angekündigt, aber ich weiß nicht, wie Sie die ActionBar aktualisieren, um den aktuellen Backstack widerzuspiegeln. Mit den ActionBar.setSelectedNavigationItem(position) Werke, sondern löst auch eine neue OnNavigationListener(), die auch eine andere FragmentTransaction schafft (nicht die Wirkung ich will). Der Code wird zur Verdeutlichung unten angezeigt. Jede Hilfe mit einer Lösung wird geschätzt.


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; 
    } 
} 

Antwort

4

Sie so etwas tun könnte:

  1. einen boolean erstellen zu verfolgen, wenn Sie ein Navigationspunkt sind die Auswahl auf der Grundlage der Zurück-Taste:

    private boolean mListIsNavigatingBack = false; 
    
  2. Überschreiben Sie onBackPressed, überprüfen Sie in der Überschreibung, ob der Backstack über Elemente verfügt. Wenn dies der Fall ist, sollten Sie sich selbst behandeln, wenn nicht, rufen Sie die Superklasse auf :

    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. Innen NavigationListener, behandeln Sie den mListIsNavigatingBack Zustand, Pop manuell zurück Stapel und ungesetzt den Zustand:

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

Vielen Dank für Ihre Anregungen, die ich mit einem Stapel implementiert. Angesichts der zusätzlichen Komplexität und der einzigartigen UX habe ich Bedenken bezüglich dieses Entwurfsmusters. Ist es besser, AddObackStack() bei Verwendung der ActionBar-Navigation nie zu verwenden? – GregM

+0

Die Liste Navigation macht es kompliziert. In der Regel wird der Backstack mehr zum Auslagern von Fragmenten in Ihrer aktuellen Ansicht verwendet. Daher könnte Ihr Anwendungsfall möglicherweise vereinfacht werden, indem Sie einfach das Fragment, das sich im Hintergrund befindet, erneut anfügen. –

Verwandte Themen