Search code examples
javaandroidandroid-fragmentsandroid-tabhostandroid-tabs

Tabhost in fragment is throwing - you must specify a way to create the tab indicator exception


I'm trying to add a tabhost in my fragment that will hold 2 child fragments. I need to add arguments to them, but seems I cannot do this because I get this in my logCat:

java.lang.IllegalArgumentException: you must specify a way to create the tab indicator.
            at android.widget.TabHost.addTab(TabHost.java:221)
            at com.myapp.fragments.CommunitySearchFragment.addTab(CommunitySearchFragment.java:247)
            at com.myapp.fragments.CommunitySearchFragment.initTabs(CommunitySearchFragment.java:151)
            at com.myapp.fragments.CommunitySearchFragment.onCreateView(CommunitySearchFragment.java:223)

This is the important code from my fragment that is doing the tabs init and provides the tabs functionality:

    private void initTabs(View mView) {
            Bundle args = new Bundle();
            mTabHost = (TabHost) mView.findViewById(android.R.id.tabhost);
            mTabHost.setup();
            TabInfo tabInfo = null;
            args.putSerializable("communityClipboards", rArray);
            addTab(mTabHost, mTabHost.newTabSpec("Tab1"), (tabInfo = new TabInfo("Tab1", CommunityClipsFragment.class, args)));

            args.putParcelableArrayList("communityClips", clipsArray);
            addTab(mTabHost, mTabHost.newTabSpec("Tab2"), (tabInfo = new TabInfo("Tab2", FragmentSearchMyClipboards.class, args)));

            // ------------------------
            mapTabInfo.put(tabInfo.tag, tabInfo);
            // Default to first tab
            onTabChanged("Tab1");
            //
            //
            mTabHost.setOnTabChangedListener(this);

        }

 private void addTab(TabHost tabHost,
                        TabHost.TabSpec tabSpec, TabInfo tabInfo) {
        // Attach a Tab view factory to the spec
        tabSpec.setContent(new TabFactory(getActivity()));
        String tag = tabSpec.getTag();

        // Check to see if we already have a fragment for this tab, probably
        // from a previously saved state. If so, deactivate it, because our
        // initial state is that a tab isn't shown.
        tabInfo.fragment = getActivity().getSupportFragmentManager()
                .findFragmentByTag(tag);
        if (tabInfo.fragment != null && !tabInfo.fragment.isDetached()) {
            FragmentTransaction ft = getActivity().getSupportFragmentManager()
                    .beginTransaction();
            ft.detach(tabInfo.fragment);
            ft.commit();
            getActivity().getSupportFragmentManager().executePendingTransactions();
        }
        tabHost.addTab(tabSpec);
    }

    @Override
    public void onTabChanged(String tag) {
        TabInfo newTab = (TabInfo) mapTabInfo.get(tag);
        if (mLastTab != newTab) {
            FragmentTransaction ft = getActivity().getSupportFragmentManager()
                    .beginTransaction();
            if (mLastTab != null) {
                if (mLastTab.fragment != null) {
                    ft.detach(mLastTab.fragment);
                }
            }
            if (newTab != null) {
                if (newTab.fragment == null) {
                    newTab.fragment = Fragment.instantiate(getActivity(),
                            newTab.clss.getName(), newTab.args);
                    ft.add(R.id.realtabcontent, newTab.fragment, newTab.tag);
                } else {
                    ft.attach(newTab.fragment);
                }
            }

            mLastTab = newTab;
            ft.commit();
            getActivity().getSupportFragmentManager().executePendingTransactions();
        }
    }

    class TabInfo {
        private String tag;
        @SuppressWarnings("rawtypes")
        private Class clss;
        private Bundle args;
        private Fragment fragment;

        @SuppressWarnings("rawtypes")
        TabInfo(String tag, Class clazz, Bundle args) {
            this.tag = tag;
            this.clss = clazz;
            this.args = args;
        }

    }

    class TabFactory implements TabHost.TabContentFactory {

        private final Context mContext;

        /**
         * @param context
         */
        public TabFactory(Context context) {
            mContext = context;
        }

        /**
         * (non-Javadoc)
         *
         * @see android.widget.TabHost.TabContentFactory#createTabContent(java.lang.String)
         */
        public View createTabContent(String tag) {
            View v = new View(mContext);
            v.setMinimumWidth(0);
            v.setMinimumHeight(0);
            return v;
        }

    }

So can someone help me make this code work?


Solution

  • According to the doc, a tab needs three things: 1) an indicator (label or label+icon), 2) content, and 3) tag. You are adding the content and tag, but the not the indicator. It seems like your call to newTabSpec would be setting the label, but actually that is just setting the tab's tag.

    The following code would work, using the tag as the label, although of course you may have a different label in mind:

    private void addTab(TabHost tabHost,
                        TabHost.TabSpec tabSpec, TabInfo tabInfo) {
        // Attach a Tab view factory to the spec
        tabSpec.setContent(new TabFactory(getActivity()));
        String tag = tabSpec.getTag();
        tabSpec.setIndicator(tag); // you may want a different label
        ...
    }