7

Ho un'app con tre schede (schede ActionBar), ognuna con un frammento alla volta.Transazione tra i frammenti solo all'interno di una scheda ActionBar

TabListener

TabsActivity

Tab1 -> ListFragment1 -> ListFragment2 -> Fragment3

Tab2 -> Tab2Fragment

Tab3 -> Tab3Fragment

Il problema è quando creo FragmentTransaction (all'interno di OnListItemClicked) da ListFragment1 a ListFragment2, i frammenti all'interno dell'altro t anche gli abs cambiano in ListFragment2.

Alla fine, voglio cambiare i frammenti solo all'interno della scheda e mantenere lo stato delle altre schede.

Sto già salvando lo stato (OnSavedInstance()). Sai cosa mi manca qui?

Parte del codice:

public class TabsActivity extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.tabs); 

     // setup Action Bar for tabs 
     ActionBar actionBar = getActionBar(); 
     actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 

     // instantiate fragment for the tab 
     Fragment networksFragment = new NetworksFragment(); 
     // add a new tab and set its title text and tab listener 
     actionBar.addTab(actionBar.newTab().setText("Tab1") 
       .setTabListener(new TabsListener(ListFragment1))); 

     // instantiate fragment for the tab 
     Fragment historyFragment = new HistoryFragment(); 
     // add a new tab and set its title text and tab listener 
     actionBar.addTab(actionBar.newTab().setText("Tab2") 
       .setTabListener(new TabsListener(Tab2Fragment))); 

     // instantiate fragment for the tab 
     Fragment settingsFragment = new SettingsFragment(); 
     // add a new tab and set its title text and tab listener 
     actionBar.addTab(actionBar.newTab().setText("Tab3") 
       .setTabListener(new TabsListener(Tab3Fragment))); 
    } 
} 

public class TabsListener implements ActionBar.TabListener { 

    private Fragment frag; 


    // Called to create an instance of the listener when adding a new tab 
    public TabsListener(Fragment networksFragment) { 
     frag = networksFragment; 
    } 

    @Override 
    public void onTabReselected(Tab arg0, FragmentTransaction arg1) { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void onTabSelected(Tab tab, FragmentTransaction ft) {  
     ft.add(R.id.fragment_container, frag, null); 
    } 

    @Override 
    public void onTabUnselected(Tab tab, FragmentTransaction ft) { 
     ft.remove(frag);   
    } 
} 

public class ListFragment1 extends ListFragment { 

    @Override 
    public void onListItemClick(ListView l, View v, int position, long id) { 

     getListView().setItemChecked(position, true); 

     ListFragment2 fragment2 = ListFragment2.newInstance(position); 

     FragmentTransaction ft = getFragmentManager().beginTransaction(); 
     ft.replace(R.id.fragment_container, fragment2); 
     ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); 
     ft.addToBackStack(null); 
     ft.commit(); 
    } 
} 

risposta

6

Non manca nulla (o mi manca troppo).

Ho cercato a lungo e duramente un modo per farlo correttamente, ma non ho trovato nulla. Quello che ho finito è scrivere la mia logica di backstack. Purtroppo il mio datore di lavoro è proprietario del mio codice, quindi non posso condividere nulla di questo, ma il mio approccio:

Creare uno enum con una voce per ciascuna scheda. Chiamiamolo TabType. Ora creare una variabile di istanza tabStacks di tipo HashMap<TabType, Stack<String>>. Ora puoi creare un'istanza di una pila per ogni scheda: ogni pila è un elenco di tag, come specificato da Fragment.getTag(). In questo modo non devi preoccuparti di memorizzare i riferimenti a Fragments e se spariranno su di te quando ruoti il ​​dispositivo. Ogni volta che hai bisogno di un riferimento a un Fragment, prendi il tag giusto fuori dallo stack e usa FragmentManager.findFragmentByTag().

Ora ogni volta che si preme un Fragment in una scheda, generare un nuovo tag (io ho usato UUID.randomUUID().toString()) e usarlo nella chiamata a FragmentTransaction.add(). Quindi spingere il tag in cima alla pila per la scheda attualmente visualizzata.

attenzione: quando si vuole spingere un nuovo frammento in cima ad un vecchio, non lo fanno remove() quello vecchio, dal momento che il FragmentManager lo considererà andato e vi sarà ripulito. Assicurati di detach() e poi attach() in seguito. Utilizzare lo remove() solo quando si esegue lo snap di uno Fragment e utilizzare solo add() la prima volta che si desidera mostrarlo.

Quindi, sarà necessario aggiungere una logica relativamente semplice al proprio TabListener.Quando una scheda è deselezionata, semplicemente peek() allo stack e detatch() il frammento associato. Quando una scheda è selezionata, peek() nella parte superiore di che stack e attach() tale frammento.

Infine, dovrai affrontare le stranezze del ciclo di vita di Attività (come le modifiche all'orientamento). Perseguire il Map di Stacks e la scheda attualmente selezionata e decomprimerlo di nuovo nel codice onCreate(). (Non si ottiene questo imballaggio e spacchettamento gratuitamente, ma è piuttosto facile da fare.) Fortunatamente il tuo enum TabType è Serializable quindi dovrebbe essere banale metterlo in un Bundle.

+1

Grazie mille! La tua risposta è l'unica su StackOverflow che mi ha aiutato a risolvere questo problema. –

+0

Non sono obbligato dal datore di lavoro, quindi ho creato un Gist contenente tutto il codice necessario: https://gist.github.com/4619215 –

Problemi correlati