【问题标题】:FragmentTabHost - No tab known for tag nullFragmentTabHost - 没有已知标签为空的标签
【发布时间】:2015-03-06 15:26:05
【问题描述】:

几天前,我在 Fragment 和 NavigationDrawer 中实现了 TabHostFramgent,我遇到了以下错误:

java.lang.IllegalStateException: No tab known for tag null

问题是一切都很完美,因为我的NavigationDrawer 的第一个项目列表是我的TabHostFragment,所以它运行完美,但问题是当我进入第二个项目的示例然后我想去回到第一个项目,每次我尝试都会崩溃。

我到处搜索,这里是SO、code.google.com 等……但我仍然没有得到正确的答案。

我的tab_host_test_2.xml看起来像:

  <android.support.v4.app.FragmentTabHost xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@android:id/tabhost"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal" />

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_weight="0" />

        <FrameLayout
            android:id="@+id/realtabcontent"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1" />
    </LinearLayout>

</android.support.v4.app.FragmentTabHost>

我的activity_main.xml 我的NavigationDrawer 看起来像:

 <android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- Framelayout to display Fragments -->
    <FrameLayout
        android:id="@+id/frame_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


    <!-- Listview to display slider menu -->
    <ListView
        android:id="@+id/list_slidermenu"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@color/list_divider"
        android:dividerHeight="1dp"
        android:listSelector="@drawable/list_selector"
        android:background="@color/list_background"/>
</android.support.v4.widget.DrawerLayout>

我的TabHostFragment.java:

    public class TabHostFragment extends Fragment {

    public TabHostFragment(){

    }
    private FragmentTabHost mTabHost;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.tab_host_test2, container, false);
        return rootView;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        mTabHost = (FragmentTabHost)view.findViewById(android.R.id.tabhost);
        mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.realtabcontent);

        mTabHost.addTab(mTabHost.newTabSpec("tab1").setIndicator("Tab1"),
                MisOfertasFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("tab2").setIndicator("Tab2"),
                RecomendacionesFragment.class, null);




    }

}

我的ActivityMain.java:

public class MainActivity extends FragmentActivity {
    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    private ActionBarDrawerToggle mDrawerToggle;
    // saber si esta abierto
    public boolean mDrawerOpened;
    // nav drawer title
    private CharSequence mDrawerTitle;
    private FragmentTabHost mTabHost;
    // used to store app title
    private CharSequence mTitle;

    //para ponerlo visible
    public MenuItem mi;

    // slide menu items
    private String[] navMenuTitles;
    private TypedArray navMenuIcons;

    private ArrayList<NavDrawerItem> navDrawerItems;
    private NavDrawerListAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        mTitle = mDrawerTitle = getTitle();

        // load slide menu items
        navMenuTitles = getResources().getStringArray(R.array.nav_drawer_items);

        // nav drawer icons from resources
        navMenuIcons = getResources()
                .obtainTypedArray(R.array.nav_drawer_icons);

        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.list_slidermenu);

        navDrawerItems = new ArrayList<NavDrawerItem>();

        // adding nav drawer items to array
        // Home
        navDrawerItems.add(new NavDrawerItem(navMenuTitles[0], navMenuIcons.getResourceId(0, -1)));
        // Find People
        navDrawerItems.add(new NavDrawerItem(navMenuTitles[1], navMenuIcons.getResourceId(1, -1)));
        // Photos
        navDrawerItems.add(new NavDrawerItem(navMenuTitles[2], navMenuIcons.getResourceId(2, -1)));
        // Communities, Will add a counter here
        navDrawerItems.add(new NavDrawerItem(navMenuTitles[3], navMenuIcons.getResourceId(3, -1)));
        // Pages
        navDrawerItems.add(new NavDrawerItem(navMenuTitles[4], navMenuIcons.getResourceId(4, -1)));
        // What's hot, We  will add a counter here
        navDrawerItems.add(new NavDrawerItem(navMenuTitles[5], navMenuIcons.getResourceId(5, -1)));
        //AyudaSugerencias
        navDrawerItems.add(new NavDrawerItem(navMenuTitles[6], navMenuIcons.getResourceId(6, -1)));
        navDrawerItems.add(new NavDrawerItem(navMenuTitles[7], navMenuIcons.getResourceId(7, -1)));


        // Recycle the typed array
        navMenuIcons.recycle();

        mDrawerList.setOnItemClickListener(new SlideMenuClickListener());

        // setting the nav drawer list adapter
        adapter = new NavDrawerListAdapter(getApplicationContext(),
                navDrawerItems);
        mDrawerList.setAdapter(adapter);

        // enabling action bar app icon and behaving it as toggle button

        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setBackgroundDrawable(new ColorDrawable(0xff1d97dd));
        getActionBar().setHomeButtonEnabled(true);

        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
                R.drawable.ic_drawer, //nav menu toggle icon
                R.string.app_name, // nav drawer open - description for accessibility
                R.string.app_name // nav drawer close - description for accessibility
        ) {
            public void onDrawerClosed(View view) {
                getActionBar().setTitle(
                        Html.fromHtml("<font color='ffffff'>"
                                + mTitle + "</font>"));

                // calling onPrepareOptionsMenu() to show action bar icons
                invalidateOptionsMenu();
                mDrawerOpened = false;
                syncState();

            }

            public void onDrawerOpened(View drawerView) {
                getActionBar().setTitle(
                        Html.fromHtml("<font color='ffffff'>"
                                + mDrawerTitle + "</font>"));

                // calling onPrepareOptionsMenu() to hide action bar icons
                invalidateOptionsMenu();
                mDrawerOpened = true;
                syncState();
            }
        };
        mDrawerLayout.setDrawerListener(mDrawerToggle);

        if (savedInstanceState == null) {
            // on first time display view for first nav item
            displayView(0);
        }
    }

    /**
     * Slide menu item click listener
     */
    private class SlideMenuClickListener implements
            ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                                long id) {
            // display view for selected nav drawer item
            displayView(position);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {


        getMenuInflater().inflate(R.menu.main, menu);


        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Fragment fragment = null;
        // toggle nav drawer on selecting action bar app icon/title
        if (mDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        // Handle action bar actions click
        switch (item.getItemId()) {
            case R.id.action_settings:
                return true;
            case R.id.ofertasRefresh:
                return true;
            case R.id.menu_search:
                return true;
            case R.id.newOffer:
                getFragmentManager().beginTransaction().replace(R.id.frame_container, new TipusNouProducte()).commit();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    /* *
     * Called when invalidateOptionsMenu() is triggered
     */
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // if nav drawer is opened, hide the action items
        boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
        menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
        if (mDrawerOpened) {
            menu.removeItem(R.id.ofertasRefresh);
            menu.removeItem(R.id.menu_search);
            menu.removeItem(R.id.newOffer);
        }
        if (!mDrawerOpened) {
            menu.add(Menu.NONE, R.id.ofertasRefresh, Menu.NONE, mTitle);
        }
        return super.onPrepareOptionsMenu(menu);

    }

    /**
     * Diplaying fragment view for selected nav drawer list item
     */
    private void displayView(int position) {
        mDrawerList.setItemChecked(position, true);
        mDrawerList.setSelection(position);
        setTitle(navMenuTitles[position]);
        mDrawerLayout.closeDrawer(mDrawerList);
        Fragment fragment = null;

        switch (position) {
            case 0:
                fragment = new TabHostFragment();
                break;
            case 1:
                fragment = new RecomendacionesFragment();
                break;
            case 2:
                fragment = new LocalizacionFragment();
                break;
            case 3:
                fragment = new ListaProductosFragment();
                break;
            case 4:
                fragment = new ConfiguracionFragment();
                break;
            case 5:
                fragment = new AyudaSugerenciasFragment();
                break;
            case 6:
                fragment = new AyudaSugerencias();
                break;

            default:

                break;
        }


        if (fragment != null) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            fragmentManager.beginTransaction()
                    .replace(R.id.frame_container, fragment).commit(); /// here says that replace android.app.Fragment in FragmentTransaction cannot be applied...

            // update selected item and title, then close the drawer
            mDrawerList.setItemChecked(position, true);
            mDrawerList.setSelection(position);
            setTitle(navMenuTitles[position]);
            mDrawerLayout.closeDrawer(mDrawerList);
        } else {
            // error in creating fragment
            Log.e("MainActivity", "Error in creating fragment");
        }
    }


    @Override
    public void setTitle(CharSequence title) {
        mTitle = title;
        getActionBar().setTitle(mTitle);

    }

    /**
     * When using the ActionBarDrawerToggle, you must call it during
     * onPostCreate() and onConfigurationChanged()...
     */

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred.
        mDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Pass any configuration change to the drawer toggls
        mDrawerToggle.onConfigurationChanged(newConfig);
    }



}

完整的LogCat 错误是:

  03-04 16:53:05.708    2232-2232/info.androidhive.slidingmenu E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: info.androidhive.slidingmenu, PID: 2232
java.lang.IllegalStateException: No tab known for tag null
        at android.support.v4.app.FragmentTabHost.doTabChanged(FragmentTabHost.java:330)
        at android.support.v4.app.FragmentTabHost.onAttachedToWindow(FragmentTabHost.java:280)
        at android.view.View.dispatchAttachedToWindow(View.java:13406)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2707)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2714)
        at android.view.ViewGroup.addViewInner(ViewGroup.java:3919)
        at android.view.ViewGroup.addView(ViewGroup.java:3733)
        at android.view.ViewGroup.addView(ViewGroup.java:3678)
        at android.view.ViewGroup.addView(ViewGroup.java:3654)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:958)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1126)
        at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:739)
        at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1489)
        at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:454)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5221)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

编辑

@Y.S. 的答案与我的要求有点不同,但它可能是一个解决方案,但它根本没有正常工作,NavigationDrawer 在TabHostFragment 下,等等...我不想改变我的布局。

【问题讨论】:

    标签: java android android-layout android-viewpager android-tabhost


    【解决方案1】:

    正如错误提示的那样

    Java:非法状态异常:没有标签为 null 的标签

    你试图初始化 TabHost 但TabHost was null。


    试试我用来初始化TabHost 的代码,它工作正常。将代码保存在onCreateView()。当您尝试在onViewCreated() 中设置FragmentTabHost 时会出现此问题,这被称为太晚了。尝试在onCreateView()中设置它,并在返回视图Object之前添加至少一个标签。

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
    
        // Create FragmentTabHost
        mTabHost = new FragmentTabHost(getActivity());
        // Locate fragment1.xml to create FragmentTabHost
        mTabHost.setup(getActivity(), getChildFragmentManager(), R.layout.fragment1);
        mTabHost.addTab(mTabHost.newTabSpec("groups").setIndicator("",getResources().getDrawable(R.drawable.tab_group_icon)),FragmentTab1.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("contacts").setIndicator("",getResources().getDrawable(R.drawable.tab_user_icon)),FragmentTab2.class, null);
    
        MainActivity.fabButton.setVisibility(View.VISIBLE);
        return mTabHost;
    }
    

    将Layout 更改为:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
    
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="0dip"
            android:layout_weight="1" />
    
        <android.support.v4.app.FragmentTabHost
            android:id="@android:id/tabhost"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
    
            <FrameLayout
                android:id="@android:id/tabcontent"
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_weight="0" />
    
        </android.support.v4.app.FragmentTabHost>
    
    </LinearLayout>
    

    希望对你有帮助。

    【讨论】:

    • 我会照你说的做,如果我来 Layout the Tabs 下降,它们有太多的填充顶部或者我不知道发生了什么,一切都很好,但是片段 1 是什么?我有mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.realtabcontent);,如果我复制粘贴你的布局,它不会让我放 realtabcontent..
    【解决方案2】:

    这里还有另一种显示选项卡的方法。

    像这样定义TabHostFragment:

    public class TabHostFragment extends Fragment implements ActionBar.TabListener{
    
        public TabHostFragment(){
    
        }
    
        AppSectionsPagerAdapter mAppSectionsPagerAdapter;
        ViewPager mViewPager;
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.tab_host_test2, container, false);
            return rootView;
        }
    
        @Override
        public void onViewCreated(View view, Bundle savedInstanceState){
            mAppSectionsPagerAdapter = new AppSectionsPagerAdapter(getChildFragmentManager());
    
            final ActionBar actionBar = ((FragmentActivity)getActivity()).getSupportActionBar();
    
            actionBar.setHomeButtonEnabled(false);
            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    
            mViewPager = (ViewPager) view.findViewById(R.id.pager);
            mViewPager.setAdapter(mAppSectionsPagerAdapter);
            mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
    
                @Override
                public void onPageSelected(int position) {
                    actionBar.setSelectedNavigationItem(position);
                }
            });
    
            for (int i = 0; i < mAppSectionsPagerAdapter.getCount(); i++) {
                actionBar.addTab(
                    actionBar.newTab()
                            .setText(mAppSectionsPagerAdapter.getPageTitle(i))
                            .setTabListener(this));
            }
        }
    
        @Override
        public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
        }
    
        @Override
        public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
            mViewPager.setCurrentItem(tab.getPosition());
        }
    
        @Override
        public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
        }
    
        public static class AppSectionsPagerAdapter extends FragmentPagerAdapter {
    
            public AppSectionsPagerAdapter(FragmentManager fm) {
                super(fm);
            }
    
            @Override
            public Fragment getItem(int i) {
                Fragment f = null;
                switch (i) {
                    case 0:
                        f = new MisOfertasFragment();
                        break;
    
                    case 1:
                        f = new RecomendacionesFragment();
                        break;
                }
    
                return f;
            }
    
            @Override
            public int getCount() {
                return 2;
            }
    
            @Override
            public CharSequence getPageTitle(int position) {
                return getFragmentTitle(position);
            }
    
            private String getFragmentTitle(int position){
                if(position == 0)
                    return "Tab 1";
                else if(position == 1)
                    return "Tab 2";
                else
                    return "";
            }
        }
    }
    

    像这样定义tab_host_test2.xml:

    <android.support.v4.view.ViewPager 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
    

    其余代码保持不变。

    试试这个。这应该可以。

    编辑:

    将此添加到displayView() 方法中:

    if(position != 0)
        getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
    

    【讨论】:

    • 嗯,现在选项卡已修复,我的滑动导航抽屉的按钮只有在我向右滑动时才会出现,这不是我要寻找的方式对不起......例如:如果我转到导航抽屉上的第 4 行,标签仍然在那里,我只想在我的第一个项目上显示标签
    • 我明白......因为有一种方法......让我编辑我的答案:)
    • 嗯..我真的不认为将actionbartab实现到NavigationDrawer,这对我来说是个好主意,它不允许用户点击图标来打开导航抽屉......对不起: ( DP :每次我回到位置 0 时,它都会因任何原因而倍增。
    • 嗯...你能添加一些正在发生的事情的截图吗?我使用它的应用程序与选项卡和导航抽屉正常工作......我认为我们可以解决问题,无论它们是什么:)
    • 当然,不客气。我还记得,如果您正在寻找一个在社交网络上共享的通用“库”,则有一个叫做 socialauth,另一个叫做 AndroidSocialNetworks。有了它们,您可以使用相同的代码在所有社交网络(如 FB、Twitter 等)上共享文件。我很久以前就用过这两个,所以不确定它们是否还能正常工作......
    【解决方案3】:

    在 .xml 文件中指定您使用此 TabHostFragment 的位置(完整路径,如 com.my.TabHostFragment)。喜欢

     <com.my.TabHostFragment
            android:id="@+id/fragmentId"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
             />
    

    【讨论】:

    • 我的 package.TabHostFragment 是什么意思?
    • 只是示例。您必须在 xml 文件中指定带有包名的 TabHostFragment。
    • 可能还有其他问题。但无论何时使用自定义组件,都必须在 xml 中指定。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多