2012-01-16 12 views
11

Tengo un código muy simple en el que utilizo la barra de acciones con fragmentos de pestañas. Funciona bien después de la carga, pero después del cambio de orientación se vuelve loco. El viejo fragmento también es visible (¿por qué?).Android Action Bar Tab con vista de desplazamiento hecha vista duplicada después del cambio de orientación

Lo siento por los textos húngaros en la imagen, pero espero que no importe. After orientation change

Adjunto el código, quizás ayude a resolver este problema.

Actividad principal:

public class Main extends Activity 
{ 
    private static ActionBar actionBar; 

    @Override 
    protected void onCreate(final Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 

     // setup action bar for tabs 
     actionBar = getActionBar(); 
     actionBar.removeAllTabs(); 
     if (actionBar.getTabCount() == 0) 
     { 
      actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 

      Tab tab = actionBar.newTab().setText(R.string.starter).setTabListener(new TabListener<Starter>(this, "starter", Starter.class)); 
      actionBar.addTab(tab); 

      tab = actionBar.newTab().setText(R.string.newword).setTabListener(new TabListener<NewWord>(this, "newwod", NewWord.class)); 
      actionBar.addTab(tab); 

      tab = actionBar.newTab().setText(R.string.feedback).setTabListener(new TabListener<Feedback>(this, "feedback", Feedback.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", getActionBar().getSelectedNavigationIndex()); 
    } 
} 

TabListener (igual que Google ejemplo):

public class TabListener<T extends Fragment> implements android.app.ActionBar.TabListener 
{ 
    private Fragment 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; 
    } 

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

    } 

    @Override 
    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 = Fragment.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); 
     } 

    } 

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

} 

Fragmento:

public class Starter extends Fragment 
{ 
    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    { 
     setRetainInstance(false); 
     return inflater.inflate(R.layout.newword, container, false); 
    } 
} 

y el diseño XML:

<?xml version="1.0" encoding="utf-8"?> 
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:padding="5dp" > 

    <LinearLayout 
     xmlns:android="http://schemas.android.com/apk/res/android" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:orientation="vertical" > 

     <TextView 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:padding="5dp" 
      android:text="@string/newword" 
      android:textAppearance="?android:attr/textAppearanceMedium" /> 

     <EditText 
      android:id="@+id/newwordtext" 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:hint="@string/wordhint" /> 

     <TextView 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:padding="5dp" 
      android:text="@string/description" 
      android:textAppearance="?android:attr/textAppearanceMedium" 
      android:textStyle="bold" /> 

     <EditText 
      android:id="@+id/descriptionwordtext" 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:hint="@string/descriptionhint" 
      android:inputType="textMultiLine" 
      android:minLines="4" /> 

     <TextView 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:padding="5dp" 
      android:text="@string/origin" 
      android:textAppearance="?android:attr/textAppearanceMedium" 
      android:textStyle="bold" /> 

     <EditText 
      android:id="@+id/origintext" 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:hint="@string/originhint" /> 

     <TextView 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:padding="5dp" 
      android:text="@string/source" 
      android:textAppearance="?android:attr/textAppearanceMedium" 
      android:textStyle="bold" /> 

     <EditText 
      android:id="@+id/sourcetext" 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:hint="@string/sourcehint" /> 

     <TextView 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:padding="5dp" 
      android:text="@string/name" 
      android:textAppearance="?android:attr/textAppearanceMedium" 
      android:textStyle="bold" /> 

     <EditText 
      android:id="@+id/nametext" 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:inputType="textPersonName" /> 

     <Button 
      android:id="@+id/sendbutton" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_gravity="right" 
      android:text="@string/send" /> 
    </LinearLayout> 

</ScrollView> 

¡Gracias de antemano!

Respuesta

5

He encontrado una respuesta utilizable en otra question.

tengo que modificar mi TabListener (lo moví en mi clase principal actividad como clase interna):

private class TabListener<T extends Fragment> implements android.app.ActionBar.TabListener 
    { 
     private Fragment 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(final Activity activity, final String tag, final Class<T> clz) 
     { 
      mActivity = activity; 
      mTag = tag; 
      mClass = clz; 
     } 

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

     @Override 
     public void onTabSelected(final Tab tab, final FragmentTransaction ft) 
     { 
      mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag); 
      if (mFragment == null) 
      { 
       mFragment = Fragment.instantiate(mActivity, mClass.getName()); 
       ft.add(android.R.id.content, mFragment, mTag); 
      } 
      else 
      { 
       ft.attach(mFragment); 
      } 
     } 

     @Override 
     public void onTabUnselected(final Tab tab, final FragmentTransaction ft) 
     { 
      if (mFragment != null) 
      { 
       ft.detach(mFragment); 
      } 
     } 
    } 

Así que antes de agregar el fragmento (de nuevo), lo compruebo existencia (y obtener su referencia) y si existe lo adjunto solo.

+1

Lo único que agregaría es que esta línea "mFragment = mActivity.getFragmentManager(). FindFragmentByTag (mTag);" También se debe agregar en el método onTabUnselected before the mFragment! = Check null. De lo contrario, funcionó muy bien! – SBerg413

+0

mFragment = mActivity.getFragmentManager(). FindFragmentByTag (mTag); Resolvió mi problema también, la clase no necesita ser interna y privada. – Goldorak84

2

Pruebe usar ft.replace (R.id.content, mFragment) en lugar de ft.attach (mFragment); en función de onTabSelected

+0

he intentado con esto...: ft.replace (android.R.id.content, mFragment); pero no ayuda (hace el mismo problema) y luego de volver a seleccionar la pestaña es mueve el contenido completo de la pestaña. – sianis

+0

Heh ...el código que funcionó para mí: 'si (fragmentManager.findFragmentById (R.id.frame_for_fragment) == null) { FragmentTransaction fragmentTransaction = fragmentManager .beginTransaction(); fragmento = new SomeFragment(); fragmentoTransaction.add (R.id.frame_for_fragment, fragment); fragmentoTransaction.commit(); } ' – Orest

+0

¿Pero cómo puedo insertar su código en mi aplicación? – sianis

0
public void onTabSelected(Tab tab, FragmentTransaction ft) 
    { 
     // Check if the fragment is already initialized 
     if (mFragment == null) 
     { 
      if(ft.findFragmentById(android.R.id.content) == null){ 
      // If not, instantiate and add it to the activity 
      mFragment = Fragment.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); 
     } 

    } 

Algo por el estilo, porque su problema es que su añadiendo el mismo fragmento en dos ocasiones, sólo tenemos que encontrar dónde ...

1

he encontrado una solución muy simple para evitar los fragmentos de la duplicación:

public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { 
     Fragment currentFragment = getFragmentManager().findFragmentByTag(CURRENT_FRAGMENT_TAG); 
     if (currentFragment == null || !currentFragment.getClass().equals(mFragment.getClass())) { 
      ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); 
      ft.add(android.R.id.content, mFragment, CURRENT_FRAGMENT_TAG); 
     } 
    } 

    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { 
     ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE); 
     ft.remove(mFragment); 
    } 

La clave de la solución está en la condición:

currentFragment == null || !currentFragment.getClass().equals(mFragment.getClass()) 

Esta condición es válida sólo si las clases de los fragmentos son diferentes. En caso de que tenga instancias diferentes de la misma clase, debe poner un atributo adicional en sus fragmentos para reconocer su función (o la asociación con y para hacer la condición! CurrentFragment.getClass(). Equals (mFragment.getClass()) true : por ejemplo, puede utilizar la función de etiqueta FragmentTransaction

adiós, Alex

0

he resuelto este con sólo mirar el fragmento en el constructor pestaña oyente

public class TabListener<T extends Fragment> implements ActionBar.TabListener 
{ 
    private Fragment fragment; 
    private final SherlockFragmentActivity activity; 
    private final String tag; 
    private final Class<T> clazz; 

    public TabListener(SherlockFragmentActivity activity, String tag, Class<T> clazz) 
    { 
     this.activity = activity; 
     this.tag = tag; 
     this.clazz = clazz; 

     FragmentManager manager = ((SherlockFragmentActivity) activity).getSupportFragmentManager(); 
     fragment = manager.findFragmentByTag(tag); 
    } 
... 
} 
Cuestiones relacionadas