5

Estoy usando el código que encontré here.¿Cómo eliminar una pestaña con la barra de acciones, viewpager y múltiples fragmentos?

public class ActionBarTabs extends SherlockFragmentActivity { 
CustomViewPager mViewPager; 
TabsAdapter mTabsAdapter; 
TextView tabCenter; 
TextView tabText; 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
      WindowManager.LayoutParams.FLAG_FULLSCREEN); 

    mViewPager = new CustomViewPager(this); 
    mViewPager.setId(R.id.pager); 

    setContentView(mViewPager); 
    ActionBar bar = getSupportActionBar(); 
    bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 
    bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); 

    mTabsAdapter = new TabsAdapter(this, mViewPager); 

    mTabsAdapter.addTab(bar.newTab().setText("Home"), 
      ToolKitFragment.class, null); 
    mTabsAdapter.addTab(bar.newTab().setText("FujiSan"), 
      FujiFragment.class, null); 
} 

public static class TabsAdapter extends FragmentPagerAdapter implements 
     ActionBar.TabListener, ViewPager.OnPageChangeListener { 
    private final Context mContext; 
    private final ActionBar mActionBar; 
    private final ViewPager mViewPager; 
    private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); 

    static final class TabInfo { 
     private final Class<?> clss; 
     private final Bundle args; 

     TabInfo(Class<?> _class, Bundle _args) { 
      clss = _class; 
      args = _args; 
     } 
    } 

    public TabsAdapter(SherlockFragmentActivity activity, ViewPager pager) { 
     super(activity.getSupportFragmentManager()); 
     mContext = activity; 
     mActionBar = activity.getSupportActionBar(); 
     mViewPager = pager; 
     mViewPager.setAdapter(this); 
     mViewPager.setOnPageChangeListener(this); 
    } 

    public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) { 
     TabInfo info = new TabInfo(clss, args); 
     tab.setTag(info); 
     tab.setTabListener(this); 
     mTabs.add(info); 
     mActionBar.addTab(tab); 
     notifyDataSetChanged(); 
    } 

    @Override 
    public int getCount() { 
     return mTabs.size(); 
    } 

    @Override 
    public Fragment getItem(int position) { 
     TabInfo info = mTabs.get(position); 
     return Fragment.instantiate(mContext, info.clss.getName(), 
       info.args); 
    } 

    @Override 
    public void onPageScrolled(int position, float positionOffset, 
      int positionOffsetPixels) { 
    } 

    @Override 
    public void onPageSelected(int position) { 
     mActionBar.setSelectedNavigationItem(position); 
    } 

    @Override 
    public void onPageScrollStateChanged(int state) { 
    } 

    @Override 
    public void onTabSelected(Tab tab, FragmentTransaction ft) { 
     Object tag = tab.getTag(); 
     for (int i = 0; i < mTabs.size(); i++) { 
      if (mTabs.get(i) == tag) { 
       mViewPager.setCurrentItem(i); 
      } 
     } 
    } 

    @Override 
    public void onTabUnselected(Tab tab, FragmentTransaction ft) { 
    } 

    @Override 
    public void onTabReselected(Tab tab, FragmentTransaction ft) { 
    } 
} 
} 

estoy tratando de modificarlo para que pueda eliminar las pestañas de forma dinámica. Intenté simplemente creando esta función:

public void removeTab(ActionBar.Tab tab) { 
     mTabs.remove(tab); 
     mActionBar.removeTab(tab); 
     notifyDataSetChanged(); 
    } 

Pero siempre obtengo un indexoutofboundsexception. ¿Alguien sabe una buena manera de hacer esto?

EDITAR

Al cambiar mi método a:

public void removeTab(ActionBar.Tab tab) { 
     mTabs.remove(tab.getTag()); 
     mActionBar.removeTab(tab); 
     notifyDataSetChanged(); 
    } 

que fue capaz de eliminar con éxito las pestañas. Sin embargo, cuando elimino una pestaña que NO ES la de la extrema derecha, ¿la vista (o fragmento?) Que se asoció con la pestaña no desaparece. En cambio, parece asociarse con la siguiente pestaña más alta. Por ejemplo, si eliminé la pestaña 0, la vista de la pestaña 0 solo se mueve a la pestaña 1. Si elimino la pestaña con la ID más alta, la pestaña y la vista se eliminan correctamente, pero luego vuelvo cuando agrego una pestaña nueva.

Es como si hubiera una lista de fragmentos en algún lugar que se asocia con las pestañas y eliminar la pestaña no elimina el fragmento. ¿Alguien tiene alguna idea de lo que está causando esto?

Edit2

He tratado de eliminar los fragmentos con:

  Fragment fragmentToRemove = getItem(tab.getPosition()); 
      destroyItem(mViewPager, tab.getPosition(), fragmentToRemove); 

y también

 Fragment fragmentToRemove = getItem(tab.getPosition()); 
     FragmentTransaction fragmentTransaction = mActivity 
       .getSupportFragmentManager().beginTransaction(); 
     fragmentTransaction.remove(fragmentToRemove); 
     fragmentTransaction.commit(); 

Pero tampoco ha funcionado hasta ahora.

Respuesta

8

¡Lo tengo!

public void removeTab(ActionBar.Tab tab) { 
    mTabs.remove(tab.getTag()); 
    mActionBar.removeTab(tab); 
    notifyDataSetChanged(); 
} 

y anular destroyItem

@Override 
    public void destroyItem(ViewGroup container, int position, Object object) { 
     // TODO Auto-generated method stub 
     super.destroyItem(container, position, object); 
     FragmentManager manager = ((Fragment) object).getFragmentManager(); 
     FragmentTransaction trans = manager.beginTransaction(); 
     trans.remove((Fragment) object); 
     trans.commit(); 
    } 

funciona perfectamente !!!

4

acabo de descubrir hoy que el verdadero truco para apoyar la inserción o extracción de las pestañas es reemplazar FragmentPagerAdapter.getItemPosition():

@Override 
public int getItemPosition(Object object) { 
    Fragment fragment = (Fragment) object; 
    for (int i = 0; i < tabInfos.size(); i++) { 
     if (tabInfos.get(i).clss == fragment.getClass()) { 
      return i; 
     } 
    } 
    // The tab must have been removed 
    return POSITION_NONE; 
} 

getItemPosition() serán llamados por el ViewPager después de haber llamado notifyDataSetChanged() (después de añadir/pestañas eliminación). El ViewPager está intentando resincronizar su caché con este adaptador. Llama al getItemPosition() por cada 'objeto' (Fragmento) que contiene, y le decimos de qué posición es ese Fragmento. Si no hay coincidencia, es porque eliminamos esa pestaña, así que devuelva POSITION_NONE.

También he encontrado que es importante anular FragmentPagerAdapter.getItemId() si inserta o quita pestañas, porque los Fragmentos se moverán hacia la izquierda y hacia la derecha. Este método se llama por FragmentPagerAdapter.instantiateItem() y se agrega a un nombre (cadena) para el artículo. Utiliza este nombre para buscar un Fragmento preexistente con un nombre coincidente (si hay uno) de otro modo instanciar uno nuevo.Aquí hay un código:

@Override 
public long getItemId(int position) { 
    TabInfo info = tabInfos.get(position); 
    // The default hashCode() implementation is based on memory address, which will be unique 
    int hash = info.clss.hashCode(); 
    return hash; 
} 
+0

Gracias. ¿Puedes compartir el resultado de no implementar estas dos anulaciones? ¿Es una cuestión de rendimiento o dará como resultado un comportamiento incorrecto? – JRun

+0

Entiendo la idea de anular estas funciones, pero ¿cuál es la llamada para eliminar realmente la pestaña de ViewPager? – gcl1

+0

Quise dirigir la pregunta anterior a @ jfritz42. Gracias. – gcl1

Cuestiones relacionadas