5

Sto usando il codice che ho trovato here.Come eliminare una scheda con barra delle azioni, viewpager e più frammenti?

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) { 
    } 
} 
} 

Sto provando a modificarlo in modo che possa eliminare le schede dinamicamente. Ho provato semplicemente creando questa funzione:

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

Ma ottengo sempre un indexoutofboundsexception. Qualcuno sa un buon modo per farlo?

EDIT

cambiando il mio metodo per:

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

sono stato in grado di rimuovere con successo le schede. Tuttavia, quando elimino una scheda che NON è quella all'estrema destra, la vista (o il frammento?) Associata alla scheda non scompare. Invece, sembra essere associato alla prossima scheda più alta. Ad esempio, se ho cancellato la scheda 0, la visualizzazione della scheda 0 si sposta solo sulla scheda 1. Se elimino la scheda con l'ID più alto, la scheda e la vista scompaiono correttamente ma TORNA INDIETRO quando aggiungo una nuova scheda.

È come se ci fosse un elenco di frammenti da qualche parte associato alle schede e l'eliminazione della scheda non elimina il frammento. Qualcuno ha idea di cosa sta causando questo?

EDIT2

Ho cercato di eliminare i frammenti con:

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

e anche

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

Ma nessuno ha funzionato finora.

risposta

8

Trovato!

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

e sovrascrivere 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(); 
    } 

funziona perfettamente !!!

4

Ho appena scoperto oggi che il vero trucco per sostenere inserire o rimuovere le schede è quello di ignorare 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() saranno chiamati dal ViewPager dopo aver chiamato notifyDataSetChanged() (dopo l'aggiunta/rimozione di schede). Lo ViewPager sta tentando di risincronizzare la cache con questo adattatore. Chiama getItemPosition() per ogni 'oggetto' (Frammento) che contiene e gli diciamo da quale posizione proviene Frammento. Se non c'è corrispondenza, è perché abbiamo eliminato quella scheda, quindi restituire POSITION_NONE.

Ho anche scoperto che è importante sovrascrivere FragmentPagerAdapter.getItemId() se si inseriscono o si rimuovono schede, poiché i frammenti si spostano a sinistra e a destra. Questo metodo è chiamato da FragmentPagerAdapter.instantiateItem() e viene aggiunto a un nome (stringa) per l'elemento. Usa questo nome per cercare un frammento preesistente con un nome corrispondente (se ce n'è uno), altrimenti istanzia uno nuovo.Ecco alcuni codici:

@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

Grazie. Puoi condividere il risultato di non implementare questi due override? È una cosa da prestazione, o si tradurrà in un comportamento scorretto? – JRun

+0

Capisco l'idea di ignorare queste funzioni, ... ma qual è la chiamata per eliminare effettivamente la scheda dal ViewPager? – gcl1

+0

Intendevo indirizzare la domanda sopra a @ jfritz42. Grazie. – gcl1

Problemi correlati