【问题标题】:Android Navigation Drawer over the tabs选项卡上的 Android 导航抽屉
【发布时间】:2013-05-23 12:07:46
【问题描述】:

我正在使用支持库中提供的新导航抽屉。将抽屉与标签一起使用时,抽屉菜单将显示在标签下方,如下所示。我如何确保抽屉菜单显示在选项卡上。 (它应该像没有标签一样显示抽屉菜单)

没有标签的抽屉菜单

带有标签的抽屉菜单

【问题讨论】:

    标签: android tabs android-actionbar navigation-drawer


    【解决方案1】:

    我遇到了同样的问题,我从 Roman Nurik(Android 团队)那里得到的答案是导航抽屉不应该与操作栏选项卡一起使用。

    讨论可以在这里找到: https://plus.google.com/u/1/116515063230772720916/posts/8dWEkFcbTFX

    【讨论】:

    • 那么谷歌游戏应用程序使用的是什么?如果您在抽屉中选择“我的游戏”,它将显示一个带有指示器的查看器,如果您再次按下抽屉,它将出现在带有指示器的查看器上方。
    • 8 个月后,许多 Google 应用仍然使用标签和导航抽屉(至少是 Play、Music 和 YouTube),所以我猜这个建议不再适用了。
    • @dpk 实际上,完整的引用是“您不应该将导航抽屉与操作栏选项卡一起使用。如果您的目标是类似于 Google Play 音乐的 UI,您应该手动实现选项卡。”所以可以在抽屉中使用标签,而不是操作栏标签。在音乐应用中,你可以看到他们在“所有音乐”和“在设备上”的操作栏中使用了微调导航样式,因此很明显库中的选项卡不能是“操作栏选项卡”,而是而不是太难的定制标签。
    • 这显然是来自 Google Android 团队的糟糕设计的设计模式
    • 他们没有为所有人修复此错误,而是在自己的应用程序中使用了自定义版本。在 Google 上感到羞耻!
    【解决方案2】:

    创建一个单独的片段,比如 TabsFragment 并将片段添加到主要活动的片段容器中。

    可以使用以下代码将选项卡添加到选项卡片段中。

    private FragmentTabHost mTabHost;
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        mTabHost = new FragmentTabHost(getActivity());
        mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.fragment1);
    
        mTabHost.addTab(mTabHost.newTabSpec("TabA").setIndicator("TabA"),
               TabA.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("TabB").setIndicator("TabB"),
                TabB.class, null);
    
        return mTabHost;
    }
    

    这里,TabA 和 TabB 是选项卡的单独片段。您可以在各自的片段中实现各自选项卡的功能。 参考:http://developer.android.com/reference/android/support/v4/app/FragmentTabHost.html

    【讨论】:

      【解决方案3】:

      我不确定 Action Bar 选项卡,但您可以使用 Pager Tab Strip 结合 Navigation Drawer 来获得类似于 Google Play Music 的导航模型,看看my post

      【讨论】:

        【解决方案4】:

        这是我使用的解决方案看起来像(完美运行): 我正在使用框架布局来交换片段,而选项卡式布局是基本片段上的选项卡。

        activity_main.xml

        <android.support.v4.widget.DrawerLayout
            android:id="@+id/drawer_layout"
            xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        
            <!--<include-->
            <!--android:id="@+id/toolbar"-->
            <!--layout="@layout/toolbar"/>-->
            <FrameLayout
                android:id="@+id/content_frame"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
        
                <LinearLayout
        
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:orientation="vertical">
        
                    <android.support.design.widget.TabLayout
                        android:id="@+id/sliding_tabs"
                        android:layout_width="match_parent"
                        scrol
                        android:layout_height="wrap_content"/>
        
                    <android.support.v4.view.ViewPager
                        android:id="@+id/viewpager"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"/>
                </LinearLayout>
            </FrameLayout>
        
            <ListView
                android:id="@+id/navList"
                android:layout_width="200dp"
                android:layout_height="match_parent"
                android:layout_gravity="left|start"
                android:background="#ffeeeeee"/>
        
        </android.support.v4.widget.DrawerLayout>
        

        【讨论】:

          【解决方案5】:

          您可以手动隐藏负责渲染选项卡的视图:

          public static void setActionBarNavigationVisibility(Activity activity, boolean visible) {
              // --- If the Tabs are BELOW ActionBar (narrow screens) --- 
              int actionViewResId = Resources.getSystem().getIdentifier("action_bar_container", "id", "android"); // @see http://stackoverflow.com/questions/20023483/how-to-get-actionbar-view
              View actionBarContainer = activity.findViewById(actionViewResId); // returns instance of com.android.internal.widget.ActionBarContainer (inaccessible)
              try {
                  Field mTabContainerField = actionBarContainer.getClass().getDeclaredField("mTabContainer");
                  if (mTabContainerField != null) {
                      mTabContainerField.setAccessible(true);
                      View mmTabContainer = (View) mTabContainerField.get(actionBarContainer);
                      if (mmTabContainer != null)
                          mmTabContainer.setVisibility(visible ? View.VISIBLE : View.GONE); // use GONE, so the mTabContainer below ActionBar does not take space in layout
                  }
              } catch (Exception e) {
                  // TODO handle exception
              }
          }
          

          只需从ActionBarDrawerToggle 的实现中调用此方法,如下所示:

          public void onDrawerSlide(View drawerView, float slideOffset) {
                  super.onDrawerSlide(drawerView, slideOffset);
                  if (slideOffset == 0) { // 0 = drawer is closed             
                      setActionBarNavigationVisibility(activity, true); //show Tabs when Drawer is closed             
                  }
              }
          
          public void onDrawerStateChanged(int newState) {
                  super.onDrawerStateChanged(newState);
                  //hides Tabs right after Drawer starts opening
                  if (DrawerLayout.STATE_DRAGGING == newState || DrawerLayout.STATE_SETTLING == newState) {
                      setActionBarNavigationVisibility(activity, false);
                  }
              }
          

          如果您在窄屏幕上使用 ActionBar.Tabs(选项卡自动显示在 ActionBar 下方),此解决方案将正常工作。但如果要处理所有其他导航场景(NavigationMode:List、CustomNavigationView 或 Tabs 直接显示在 ActionBar 中),第一种方法需要处理所有这些可能性:

          public static void setActionBarNavigationVisibility(Activity activity, boolean visible) {
              try {
                  /* 1. --- If the navigation items are showing in ActionBar directly. We have 3 options Spinner, Tabs, and CustomNav ---
                   (When Tabs are showing BELOW ActionBar, is handled at the end) */
                  int actionViewResId = Resources.getSystem().getIdentifier("action_bar", "id", "android"); // @see http://stackoverflow.com/questions/20023483/how-to-get-actionbar-view
                  View actionBarView = activity.findViewById(actionViewResId); // returns instance of com.android.internal.widget.ActionBarView (inaccessible)
                  if (actionBarView != null) {
                      int visibility = visible ? View.VISIBLE : View.INVISIBLE; // not GONE, so it still takes space in ActionBar layout
          
                      // handle tabs navigation
                      Field mTabScrollViewField = actionBarView.getClass().getDeclaredField("mTabScrollView");
                      if (mTabScrollViewField != null) {
                          mTabScrollViewField.setAccessible(true);
                          View mTabScrollView = (View) mTabScrollViewField.get(actionBarView); // instance of com.android.internal.widget.ScrollingTabContainerView (inaccessible)
                          if (mTabScrollView != null)
                              mTabScrollView.setVisibility(visibility);
                      }
          
                      // handle Spinner navigation
                      Field mSpinnerField = actionBarView.getClass().getDeclaredField("mSpinner"); // resp. mListNavLayout
                      if (mSpinnerField != null) {
                          mSpinnerField.setAccessible(true);
                          View mSpinner = (View) mSpinnerField.get(actionBarView); // instance of android.widget.Spinner
                          if (mSpinner != null)
                              mSpinner.setVisibility(visibility);
                      }
          
                      // handle Custom navigation
                      Field mCustomNavViewField = actionBarView.getClass().getDeclaredField("mCustomNavView"); // resp. mListNavLayout
                      if (mCustomNavViewField != null) {
                          mCustomNavViewField.setAccessible(true);
                          View mCustomNavView = (View) mCustomNavViewField.get(actionBarView);
                          if (mCustomNavView != null)
                              mCustomNavView.setVisibility(visibility);
                      }
                  }
                  // 2. --- If the Tabs are BELOW ActionBar (narrow screens) ---          
                  ViewParent actionBarContainer = actionBarView.getParent(); // parent of ActionBarView is com.android.internal.widget.ActionBarContainer (inaccessible)
                  Field mTabContainerField = actionBarContainer.getClass().getDeclaredField("mTabContainer");
                  if (mTabContainerField != null) {
                      mTabContainerField.setAccessible(true);
                      View mmTabContainer = (View) mTabContainerField.get(actionBarContainer);
                      if (mmTabContainer != null)
                          mmTabContainer.setVisibility(visible ? View.VISIBLE : View.GONE); // now use GONE, so the mTabContainer below Actionbar does not take space in layout
                  }
          
              } catch (Exception ex) {
                  // TODO Handle exception...         
              }
          }
          

          【讨论】:

            【解决方案6】:

            WordPress Android 版本有你所说的问题的实现。

            他们开发了一个名为“Horizo​​ntalTabView”的 TabView 模拟版本。他们为什么做这个和你(也是我)需要的完全一样。

            WordPress github: https://github.com/WordPress/WordPress

            相关来源:

            • Horizo​​ntalTabView.java
            • WPActionBarActivity.java
            • res/theme_browser_activity.xml

            希望这个提示对您有所帮助。

            【讨论】:

              【解决方案7】:

              我认为现在问问题已经太晚了,但仍然如此。 如果您已经在使用导航抽屉并想要导航选项卡,请将这两个文件包含在您的项目文件夹中:

              1) SlidingTabLayout.java http://developer.android.com/samples/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.html

              2) SlidingTabStrip.java http://developer.android.com/samples/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabStrip.html

              在导航抽屉片段中,包括以下内容:

              private SlidingTabLayout mSlidingTabLayout;
                  private  SamplePagerAdapter_tasks mPagerAdapter;
                  private ViewPager mViewPager;
              
                  public void onViewCreated(View view, Bundle savedInstanceState) {
                      // BEGIN_INCLUDE (setup_viewpager)
                      // Get the ViewPager and set it's PagerAdapter so that it can display items
                      //fragment manager of a fragment,Return a private FragmentManager for placing and managing Fragments inside of this Fragment.
              
                      mPagerAdapter = new SamplePagerAdapter_tasks(getChildFragmentManager(),Titles of Tabs(array of string),Numboftabs (integer));
                      mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
                      mViewPager.setAdapter(mPagerAdapter);
              
                      // Give the SlidingTabLayout the ViewPager, this must be done AFTER the ViewPager has had
                      // it's PagerAdapter set.
                      mSlidingTabLayout = (SlidingTabLayout) view.findViewById(R.id.sliding_tabs);
                      mSlidingTabLayout.setDistributeEvenly(true); // this helps to all the tabs on screen to take equal spaces (eg. if 3 tabs each would take one-third of the total space on the screen)
              
                      mSlidingTabLayout.setViewPager(mViewPager);
              
                      // END_INCLUDE (setup_slidingtablayout)
                  }
              

              希望对你有帮助!

              【讨论】:

                【解决方案8】:

                在我的 AppCompatActivity 中添加:

                DrawerLayout drawerLayoutMenu =(DrawerLayout) findViewById(R.id.drawer_layout_menu);
                RelativeLayout mDrawerPane =(RelativeLayout) findViewById(R.id.drawerPane);
                

                我在工具栏菜单图标上调用它

                if (drawerLayoutMenu.isDrawerOpen(mDrawerPane)) {
                    drawerLayoutMenu.closeDrawer(mDrawerPane);
                } else {
                        drawerLayoutMenu.openDrawer(mDrawerPane);
                }
                

                xml文件

                <android.support.v4.widget.DrawerLayout
                        android:id="@+id/drawer_layout_menu"
                        xmlns:android="http://schemas.android.com/apk/res/android"
                        xmlns:app="http://schemas.android.com/apk/res-auto"
                        xmlns:tools="http://schemas.android.com/tools"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent">
                
                        <FrameLayout
                            android:id="@+id/content_frame"
                            android:layout_width="match_parent"
                            android:layout_height="match_parent">
                
                            <LinearLayout
                                android:layout_width="match_parent"
                                android:layout_height="match_parent"
                                android:orientation="vertical">
                
                                <android.support.v7.widget.Toolbar
                                    android:id="@+id/toolbar"
                                    android:layout_width="match_parent"
                                    android:layout_height="?attr/actionBarSize"
                                    android:background="?attr/colorPrimary"
                                    app:layout_scrollFlags="enterAlways"
                                    app:popupTheme="@style/AppTheme.PopupOverlay">
                
                                </android.support.v7.widget.Toolbar>
                
                                <android.support.design.widget.TabLayout
                                    android:id="@+id/tabs"
                                    android:layout_width="match_parent"
                                    android:layout_height="wrap_content"/>
                
                                <android.support.v4.view.ViewPager
                                    android:id="@+id/container"
                                    android:layout_width="match_parent"
                                    android:layout_height="match_parent"/>
                            </LinearLayout>
                        </FrameLayout>
                
                        <!--for menu-->
                
                        <RelativeLayout
                            android:id="@+id/drawerPane"
                            android:layout_width="270dp"
                            android:layout_height="match_parent"
                            android:orientation="vertical"
                            android:background="#fff"
                            android:layout_gravity="left|start">
                
                            <!--you can add a ListView-->
                
                        </RelativeLayout>
                
                    </android.support.v4.widget.DrawerLayout>
                

                【讨论】:

                  【解决方案9】:

                  Actionbar Navigaton Drawer 和 SwipeTabs 不能同时使用。您应该通过简单的 Tabhosts 使用 Actionbar 和 swipetabs 来实现 Navigation Drawer。您可以将 Tabhost 用于选项卡,并将片段用于每个选项卡的内部视图。片段应该通过 viewpager 来提供滚动/滑动效果。通过它们的方法将选项卡和 viewpager 相互连接

                  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:orientation="vertical" >
                  
                  <TabHost
                      android:id="@+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" >
                  
                          <HorizontalScrollView
                              android:layout_width="fill_parent"
                              android:layout_height="wrap_content"
                              android:fillViewport="true"
                              android:scrollbars="none" >
                  
                              <TabWidget
                                  android:id="@android:id/tabs"
                                  android:layout_width="wrap_content"
                                  android:layout_height="wrap_content" >
                              </TabWidget>
                          </HorizontalScrollView>
                  
                          <FrameLayout
                              android:id="@android:id/tabcontent"
                              android:layout_width="match_parent"
                              android:layout_height="match_parent" >
                  
                              <android.support.v4.view.ViewPager
                                  android:id="@+id/viewPager_home"
                                  android:layout_width="match_parent"
                                  android:layout_height="match_parent" />
                          </FrameLayout>
                      </LinearLayout>
                  </TabHost>
                  

                  【讨论】:

                  • TabHost 仅适用于活动。您必须将 FragmentTabHost 用于片段。 ViewPager 也不能放置在您显示的位置!