2012-05-08 3 views
12

Sto utilizzando ActionBarSherlock per implementare uno ActionBar con schede nella mia applicazione. Quando avvio l'app e passa da scheda a scheda, tutto è a posto. Tuttavia, quando si passa dalla modalità verticale alla modalità orizzontale, il contenuto della scheda che era l'ultimo attivo rimane visibile. La modifica in un'altra scheda comporta il disegno del nuovo contenuto sulla parte superiore del vecchio contenuto (vedi immagine).Il contenuto della scheda rimane visibile dopo aver modificato la scheda dopo il cambio di orientamento

enter image description here

mia classe principale:

public class TreinVerkeer extends SherlockFragmentActivity { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setupTabs(savedInstanceState); 

    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     MenuInflater inflater = getSupportMenuInflater(); 
     inflater.inflate(R.menu.menu, menu); 
     return true; 
    } 

    private void setupTabs(Bundle savedInstanceState) { 
     ActionBar actionBar = getSupportActionBar(); 
     actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 

     Tab tab = actionBar.newTab().setText("STATIONS").setTabListener(new TabListener<StationsFragment>(this, "stations", StationsFragment.class)); 
     actionBar.addTab(tab); 

     tab = actionBar.newTab().setText("ROUTE").setTabListener(new TabListener<RouteFragment>(this, "route", RouteFragment.class)); 
     actionBar.addTab(tab); 

     tab = actionBar.newTab().setText("DELAYS").setTabListener(new TabListener<DelaysFragment>(this, "delays", DelaysFragment.class)); 
     actionBar.addTab(tab); 

     if (savedInstanceState != null) { 
      actionBar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0)); 
     } 
    } 

    @Override 
    protected void onSaveInstanceState(Bundle outState) { 
     super.onSaveInstanceState(outState); 
     outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex()); 
    } 
} 

Il TabListener (da "Adding Navigations Tabs" on the Android developer site con alcune lievi modifiche):

public class TabListener<T extends SherlockFragment> implements com.actionbarsherlock.app.ActionBar.TabListener { 
    private SherlockFragment mFragment; 
    private final Activity mActivity; 
    private final String mTag; 
    private final Class<T> mClass; 

    /** 
    * Constructor used each time a new tab is created. 
    * 
    * @param activity 
    *   The host Activity, used to instantiate the fragment 
    * @param tag 
    *   The identifier tag for the fragment 
    * @param clz 
    *   The fragment's Class, used to instantiate the fragment 
    */ 
    public TabListener(Activity activity, String tag, Class<T> clz) { 
     mActivity = activity; 
     mTag = tag; 
     mClass = clz; 
    } 

    /* The following are each of the ActionBar.TabListener callbacks */ 

    public void onTabSelected(Tab tab, FragmentTransaction ft) { 
     // Check if the fragment is already initialized 
     if (mFragment == null) { 
      // If not, instantiate and add it to the activity 
      mFragment = (SherlockFragment) SherlockFragment.instantiate(mActivity, mClass.getName()); 
      ft.add(android.R.id.content, mFragment, mTag); 
     } else { 
      // If it exists, simply attach it in order to show it 
      ft.attach(mFragment); 
     } 
    } 

    public void onTabUnselected(Tab tab, FragmentTransaction ft) { 
     if (mFragment != null) { 
      // Detach the fragment, because another one is being attached 
      ft.detach(mFragment); 
     } 
    } 

    public void onTabReselected(Tab tab, FragmentTransaction ft) { 
     // User selected the already selected tab. Usually do nothing. 
    } 
} 

E StationsFragment (RouteFragment e DelaysFragment sono gli stessi, con la sola testo differente)

public class StationsFragment extends SherlockFragment { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     return inflater.inflate(R.layout.stationsfragment, container, false); 
    } 
} 

Con che il file di layout per StationsFragment:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" > 

    <TextView 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:text="Stations" /> 

</LinearLayout> 

E infine il file manifesto:

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.myapp" 
    android:versionCode="1" 
    android:versionName="1.0" > 

    <uses-sdk 
     android:minSdkVersion="8" 
     android:targetSdkVersion="15" /> 

    <application 
     android:icon="@drawable/ic_launcher" 
     android:label="@string/app_name" > 
     <activity 
      android:name=".TreinVerkeer" 
      android:label="@string/app_name" 
      android:theme="@style/Theme.Sherlock.Light" > 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN" /> 

       <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
     </activity> 
    </application> 

</manifest> 

Ho avuto lo stesso problema prima subito quando si avvia l'applicazione (quindi senza nemmeno cambiando l'orientamento), questo è stato risolto rimuovendo setContentView(R.layout.main) nel onCreate della classe principale. Non riesco a trovare una soluzione per questo tuttavia. Qualcuno mi può aiutare con questo?

+0

[ 'FragmentTabs.java'] (https://github.com/JakeWharton/ActionBarSherlock/blob/master/samples/fragments/src/com/actionbarsherlock/sample/fragments/FragmentTabs.java) –

risposta

19

FragmentManager ripristinerà automaticamente qualsiasi frammento (e cronologia) è stato visualizzato correntemente su una modifica di configurazione. Chiama findFragmentByTag per verificare se esiste già un'istanza del frammento di destinazione prima di creare e allegare una nuova istanza.

15

Grazie a Jake, ho aggiornato il metodo onTabSelected in questo modo:

public void onTabSelected(Tab tab, FragmentTransaction ft) { 
    SherlockFragment preInitializedFragment = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag); 

    // Check if the fragment is already initialized 
    if (mFragment == null && preInitializedFragment == null) { 
     // If not, instantiate and add it to the activity 
     mFragment = (SherlockFragment) SherlockFragment.instantiate(mActivity, mClass.getName()); 
     ft.add(android.R.id.content, mFragment, mTag); 
    } else if (mFragment != null) { 
     // If it exists, simply attach it in order to show it 
     ft.attach(mFragment); 
    } else if (preInitializedFragment != null) { 
     ft.attach(preInitializedFragment); 
     mFragment = preInitializedFragment; 
    } 
} 

Questa risposta è per motivi di chiarezza solo, i crediti vanno a Jake :)

+3

Ancora , ti meriti puntelli anche per la pubblicazione di questo codice. È molto utile Grazie :) – gnobal

5

Così come le modifiche Niek ha pubblicato, ci sono un paio di cambiamenti banali che devi fare. Principalmente solo cambiando attività in SherlockFragmentActivity.

Per il beneficio degli altri, ecco la mia versione finale che sembra funzionare correttamente.

public static class TabListener<T extends SherlockFragment> implements ActionBar.TabListener 
    { 
     private SherlockFragment mFragment; 
     private final SherlockFragmentActivity mActivity; 
     private final String mTag; 
     private final Class<T> mClass; 

     /** Constructor used each time a new tab is created. 
     * @param activity The host Activity, used to instantiate the fragment 
     * @param tag The identifier tag for the fragment 
     * @param clz The fragment's Class, used to instantiate the fragment 
     */ 
     public TabListener(Activity activity, String tag, Class<T> clz) 
     { 
     mActivity = (SherlockFragmentActivity) activity; 
     mTag = tag; 
     mClass = clz; 
     } 


     public void onTabSelected(Tab tab, FragmentTransaction ft) 
     { 
     // Check if the fragment has already been initialised 
     SherlockFragment preInitializedFragment = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag); 
     if (mFragment != null) 
     { 
      // If it exists, simply attach it in order to show it 
      ft.attach(mFragment); 
     } 
     else if (preInitializedFragment != null) 
     { 
      mFragment = preInitializedFragment; 
      ft.attach(mFragment); 
     } 
     else 
     { 
      // Not found, so instantiate and add it to the activity 
      mFragment = (SherlockFragment) SherlockFragment.instantiate(mActivity, mClass.getName()); 
      ft.add(android.R.id.content, mFragment, mTag); 
     } 
     } 


     public void onTabUnselected(Tab tab, FragmentTransaction ft) 
     { 
     if (mFragment != null) { 
      // Detach the fragment, because another one is being attached 
      ft.detach(mFragment); 
     } 
     } 


     public void onTabReselected(Tab tab, FragmentTransaction ft) 
     { 
     // User selected the already selected tab. Usually do nothing. 
     } 
    } 
+0

Considerando lo stesso caso di cui sopra ho un Sherlock Listfragment e Sherlock Fragment. Come si fa a rendere generico il listener delle schede per supportare sia la lista che il frammento normale? –