Search code examples
androidandroid-fragmentsandroid-viewpageractionbarsherlock

How to delete a tab with actionbar, viewpager, and multiple fragments?


I'm using code I found here.

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

I'm trying to modify it so that I can delete tabs dynamically. I tried by simply creating this function:

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

But I always get an indexoutofboundsexception. Does anyone know a good way to do this?

EDIT

By changing my method to:

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

I was able to successfully remove tabs. However, when I delete a tab that IS NOT the one on the far right, the view (or fragment?) that was associated with the tab doesn't go away. Instead, it seems to become associated with the next highest tab. For instance, if I deleted tab 0, tab 0's view just moves to tab 1. If I delete the tab with the highest ID then the tab and view go away correctly but then COME BACK when I add a new tab.

It's as if there's a list of fragments somewhere that is being associated with the tabs and deleting the tab doesn't delete the fragment. Does anyone have any idea what's causing this?

EDIT2

I've tried to delete the fragments with:

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

and also

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

But neither has worked so far.


Solution

  • Got it!

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

    and override 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();
        }
    

    Works perfectly!!!