Dynamically add and remove tabs in TabLayout(material design) android

66,946

Solution 1

Remove tab from TabLayout

...
public void removeTab(int position) {
    if (mTabLayout.getTabCount() >= 1 && position<mTabLayout.getTabCount()) {
          mTabLayout.removeTabAt(position);
          mPagerAdapter.removeTabPage(position);
    }
}
...

Add a removeTabPage method to your PagerAdapter

...
public void removeTabPage(int position) {
    if (!tabItems.isEmpty() && position<tabItems.size()) {
          tabItems.remove(position);
          notifyDataSetChanged();
    }
}
...

Add a Tab

...
private void addTab(String title) {
        mTabLayout.addTab(mTabLayout.newTab().setText(title));
        mPagerAdapter.addTabPage(title);
}
...

Add a addTabPage method to your PagerAdapter

...
public void addTabPage(String title) {
      tabItems.add(title);
      notifyDataSetChanged();
}
...

Check out this sample code for a full example: ...samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutUsage.java

Solution 2

With the new support library (I'm using 23.2.1) you should only add to the Viewpager and not the TabLayout (otherwise you end up with double tabs and other funky behavior). So to update TouchBoarder's answer:

Add a removeTabPage method to your PagerAdapter

public void removeTabPage(int position) {
    if (!tabItems.isEmpty() && position<tabItems.size()) {
          tabItems.remove(position);
          notifyDataSetChanged();
    }
}

Add a addTabPage method to your PagerAdapter

public void addTabPage(String title) {
      tabItems.add(title);
      notifyDataSetChanged();
}

Solution 3

In addition to existing answers, to remove all tabs from tabLayout.

tabLayout.removeAllTabs();

Solution 4

You can add dynamic tabs like this :

 public void addTabs(){
    for(YourClassModel tabName: tabsName){
        Log.i("ActivityClass","tabName"+tabName);
        tabLayout.addTab(tabLayout.newTab().setText(tabName.getName()));

    }
Share:
66,946
Ruban
Author by

Ruban

I am an Android development specialist, who has been a key player in executing the development of mobile applications in the domains like e-commerce, Augmented reality, Social networking, Banking, Gaming, etc. I have also worked on porting C++ libraries to Android using NDK and JNI .  Programming Languages : Android SDK, Android NDK, JavaSE, Metaio SDK  Repository : GIT, Tortoise SVN, Rabbit VCS  Development Tools : Eclipse ,Net Beans ,Visual Studio ,Kony Studio  Subject of Exposure : Android SDK, Android NDK, Java, Kony

Updated on July 09, 2022

Comments

  • Ruban
    Ruban almost 2 years

    I have a TabLayout and inside that I have ViewPager. I need to dynamically add and remove tab in tablayout(material design). I can able to add the tabs dynamically but while removing the tab, tab is removing correctly. But viewpager last item is deleted. So tab is not showing specific fragment. FYI i have used FragmentPagerAdapter.

    I have followed this tutorial to implement this

    https://androidbelieve.com/navigation-drawer-with-swipe-tabs-using-design-support-library

    public class TabFragment extends Fragment {
    
        public static TabLayout tabLayout;
        public static ViewPager viewPager;
        public static int int_items = 2;
        private MyNewsFragment mMyNewsFragment;
        private ArrayList<TabFragmentModelClass> mFragmentArrayList;
        private TabLayoutAdapter mTabLayoutAdapter;
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    
            mMyNewsFragment = new MyNewsFragment();
            /**
             *Inflate tab_layout and setup Views.i;;a
             */
            View x = inflater.inflate(R.layout.tab_layout, null);
            tabLayout = (TabLayout) x.findViewById(R.id.tabs);
            tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);  // scorllable tab
            tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);  // tab name fill parent
            viewPager = (ViewPager) x.findViewById(R.id.viewpager);
            mFragmentArrayList = new ArrayList<>();
            mFragmentArrayList.add(new TabFragmentModelClass(new MyNewsSelectionFragment(), "", ""));
            mFragmentArrayList.add(new TabFragmentModelClass(mMyNewsFragment, "", getResources().getString(R.string.mynews)));
            mFragmentArrayList.add(new TabFragmentModelClass(new BreakingNewsFragment(), "", getResources().getString(R.string.breakingnews)));
    
            // Selected news from shared preference
            ArrayList<MyNewsSharedPreferenceModelClass> tempSharedPreferenceModelClass = new MyNewsSharedPreferenceClass().loadFavorites(getActivity());
            for (int i = 0; i < tempSharedPreferenceModelClass.size(); i++) {
                mFragmentArrayList.add(new TabFragmentModelClass(new CategoreyNewsFragment(tempSharedPreferenceModelClass.get(i).getmCatID()), tempSharedPreferenceModelClass.get(i).getmCatID(),
                        tempSharedPreferenceModelClass.get(i).getmCatName()));
            }
    
    
     }
    
    
            /**
             *Set an Apater for the View Pager
             */
            mTabLayoutAdapter = new TabLayoutAdapter(getChildFragmentManager(), mFragmentArrayList);
            viewPager.setAdapter(mTabLayoutAdapter);
            viewPager.setOffscreenPageLimit(mFragmentArrayList.size());
            tabLayout.setupWithViewPager(viewPager);
    
    
            viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                }
    
                @Override
                public void onPageSelected(int position) {
                    tabLayout.getTabAt(position);
                }
    
                @Override
                public void onPageScrollStateChanged(int state) {
                    if (state == 1) {
                        updateMyNewsFragment();
                    }
                }
            });
    
            /**
             * Now , this is a workaround ,
             * The setupWithViewPager dose't works without the runnable .
             * Maybe a Support Library Bug .
             */
    
            tabLayout.post(new Runnable() {
                @Override
                public void run() {
    
                    tabLayout.getTabAt(0).setIcon(R.mipmap.mynewselection);
    
                    tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
                        @Override
                        public void onTabSelected(TabLayout.Tab tab) {
                            viewPager.setCurrentItem(tab.getPosition());
                            switch (tab.getPosition()) {
                                case 1:
    
                                    System.out.println("000000000000000000000 ");
                                    updateMyNewsFragment();
                                    break;
                            }
                        }
    
                        @Override
                        public void onTabUnselected(TabLayout.Tab tab) {
                        }
    
    
                        @Override
                        public void onTabReselected(TabLayout.Tab tab) {
                        }
                    });
    
                }
            });
            return x;
        }
    
        /**
         * update the mynews selection
         * this method trigger from the MainNewsActivity
         */
        public void updateMyNewsFragment() {
            if (ApplicationController.getInstance().getBoolPref(CommonVariableInterFace.isNewsSelected)) {
                mMyNewsFragment.sendMyNewsRequest();
                ApplicationController.getInstance().setBoolPref(CommonVariableInterFace.isNewsSelected, false);
            }
        }
    
        /**
         * update the tab values
         * this method trigger from the MainNewsActivity
         * if value is zero need to add in tab
         * if value is one need to remove in tab
         */
        public void updateTabvalue(String catId, String catName, int value) {
    
                if (value == 0) { // add the value in tab
    
                    mFragmentArrayList.add(new TabFragmentModelClass(new CategoreyNewsFragment(catId), catId,
                            catName));
                }  else {      // Removing the tab
                    for (int i = 0; i < mFragmentArrayList.size(); i++) {
                        if (mFragmentArrayList.get(i).getmCatID().equalsIgnoreCase(catId)) {
    
                            Log.i("-----same id ", catId);
                            mFragmentArrayList.remove(i);
                            mTabLayoutAdapter = new TabLayoutAdapter(getChildFragmentManager(), mFragmentArrayList);
                            viewPager.setAdapter(mTabLayoutAdapter);
                        }
                    }
                }
    
                mTabLayoutAdapter.notifyDataSetChanged();
                viewPager.setOffscreenPageLimit(mFragmentArrayList.size());
                tabLayout.getTabAt(0).setIcon(R.mipmap.mynewselection);
                 tabLayout.setupWithViewPager(viewPager);
    
    
                tabLayout.post(new Runnable() {
                    @Override
                    public void run() {
    
                        tabLayout.getTabAt(0).setIcon(R.mipmap.mynewselection);
    
                        tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
                            @Override
                            public void onTabSelected(TabLayout.Tab tab) {
                                viewPager.setCurrentItem(tab.getPosition());
                                switch (tab.getPosition()) {
                                    case 1:
                                        updateMyNewsFragment();
                                        break;
                                }
                            }
    
                            @Override
                            public void onTabUnselected(TabLayout.Tab tab) {
                            }
    
    
                            @Override
                            public void onTabReselected(TabLayout.Tab tab) {
                            }
                        });
    
                    }
                });
        }
    
        public void openSpecificTab() {
    
    //        tabLayout.settab
    //        tabLayout.se
        }
    }
    

    Adapter code:

    public class TabLayoutAdapter extends FragmentPagerAdapter {
    
        private long baseId = 0;
        ArrayList<TabFragmentModelClass> fragmentAdapterArrayList;
    
        public TabLayoutAdapter(FragmentManager fm, ArrayList<TabFragmentModelClass> fragmentArrayList) {
            super(fm);
            fragmentAdapterArrayList = fragmentArrayList;
        }
    
        @Override
        public Fragment getItem(int position) {
    
            if (position == 0)
                return fragmentAdapterArrayList.get(position).getmFragment();
            if (position == 1)
                return fragmentAdapterArrayList.get(position).getmFragment();
            if (position == 2)
                return fragmentAdapterArrayList.get(position).getmFragment();
    
            return new CategoreyNewsFragment().newInstance(fragmentAdapterArrayList.get(position).getmCatID());
        }
    
        @Override
        public int getCount() {
            return fragmentAdapterArrayList.size();
        }
    
    
        //this is called when notifyDataSetChanged() is called
        @Override
        public int getItemPosition(Object object) {
            // refresh all fragments when data set changed
            return TabLayoutAdapter.POSITION_NONE;
        }
    
    
        @Override
        public long getItemId(int position) {
            // give an ID different from position when position has been changed
            return baseId + position;
        }
    
        /**
         * Notify that the position of a fragment has been changed.
         * Create a new ID for each position to force recreation of the fragment
         *
         * @param n number of items which have been changed
         */
        public void notifyChangeInPosition(int n) {
            // shift the ID returned by getItemId outside the range of all previous fragments
            baseId += getCount() + n;
        }
    
        /**
         * //     * This method returns the title of the tab according to the position.
         * //
         */
    
        @Override
        public CharSequence getPageTitle(int position) {
            return fragmentAdapterArrayList.get(position).getmCatName();
        }
    }
    
  • Ruban
    Ruban over 8 years
    Thanks dude that was useful
  • Zvi
    Zvi about 8 years
    I tried the above but it did not work for me. After calling removeTab(2) on a viewpager with 5 fragments I get the error java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getLeft()' on a null object reference @Ruban
  • TouchBoarder
    TouchBoarder about 8 years
    @Zvi this error looks like you are trying to call View.getLeft() on a View that is not there, try and find out why? did the call to removeTab(2) remove the reference to this view?
  • Zvi
    Zvi about 8 years
    I solved the issue. I was calling removeTab() from within onTabSelected(). Once I moved it to the main code of the activity the problem disappeared. Thanks
  • Zvi
    Zvi about 8 years
    I now ran into another problem. After removing Tab(2), Tab(3) shows instead of Tab(2), which is exactly what I want, including the proper value of a text field of the fragment and the proper list in a listview.. However, if I swipe to Tab(1) and then back to Tab(2) the removed fragment text field appears and no listview is displayed - I suspect that maybe the removed fragment is displayed (it's listview is empty)' although it is no longer in the list of the adapter, as I checked it in the debugger.
  • Zvi
    Zvi about 8 years
    Further investigation revealed that the fragment that was associated with the removed tag, its methods onCreateView, onViewStateRestored and onResume were called, although it is no longer on the list of the adapter. Moreover, these methods of the next fragment (that it's tab is now tab(2) were called just before the removed frag
  • Zvi
    Zvi about 8 years
    To explain it better: FragmentA belogs to Tab(2) and FragmentB to Tab(3) . When I remove Tab(2) I expect that FragmentB will be called when I now use Tab(2). However, the methods of FragmentA (onCreateView, onViewStateRestored, onResume) were called after the removal of Tab(2), although it is no longer on the list of the adapter. Moreover, these methods of FragmentB were also called but just before the FragmentA methods were called. It's looks to me that due to the caching of fragments in memory, the system stills think that FragmentA is valid (it is to the right of FragmentB).
  • Zvi
    Zvi about 8 years
    Issue solved by using FragmentStatePagerAdapter instead of FragmentPagerAdapter
  • Zulqurnain Jutt
    Zulqurnain Jutt over 7 years
    what if i don't have a page adapter ? and only tab layout?
  • Monster Brain
    Monster Brain over 5 years
    @ZulqurnainJutt: I think you can do that like this TabLayout.Tab tab = tabLayout.newTab().setText("General"); tabLayout.addTab(tab);