zoukankan      html  css  js  c++  java
  • Android Navigation Drawer(导航抽屉)

    Google I/O 2013 Android 更新了Support库,新版本的Support库中新加入了几个比较重要的功能。

    • 添加 DrawerLayout 控件,支持创建  Navigation Drawer模式。可以设置从左边划出菜单或者右边,也可以左右菜单同时存在。
    • 添加 SlidingPaneLayout 控件来支持各种屏幕上的摘要、详情界面模式。比如 Gmail邮件列表和单个邮件详情界面。当在手机上显示的时候,邮件列表和详情界面分别为两个界面;当在平板上显示的时候,则为一个界面。
    • 添加 ActionBarDrawerToggle 工具类,方便把 DrawerLayout 和 ActionBar 功能结合起来。


    具体可参考以下链接

    Android Navigation Drawer Design :http://developer.android.com/design/patterns/navigation-drawer.html

    Android Navigation Drawer 教程:  Android Navigation Drawer Designhttp://developer.android.com/training/implementing-navigation/nav-drawer.html


    下面来介绍下如何使用 DrawerLayout 控件来实现抽屉菜单

    Demo 运行效果如下所示


    未打开抽屉状态





    打开抽屉菜单后



    创建Drawer Layout
    在需要抽屉菜单的界面,用DrawerLayout 作为界面根控件。在DrawerLayout里面第一个View为当前界面主内容;第二个和第三个View为抽屉菜单内容。如果当前界面只需要一个抽屉菜单,则第三个View可以省略。
    下面的例子中DrawerLayout里面包含两个View,第一个FrameLayout中是当前界面主要内容显示区域(使用Fragment填充);第二个ListView为抽屉菜单。


    1. <android.support.v4.widget.DrawerLayout  
    2.     xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:id="@+id/drawer_layout"  
    4.     android:layout_width="match_parent"  
    5.     android:layout_height="match_parent">  
    6.   
    7.     <!-- As the main content view, the view below consumes the entire  
    8.          space available using match_parent in both dimensions. -->  
    9.     <FrameLayout  
    10.         android:id="@+id/content_frame"  
    11.         android:layout_width="match_parent"  
    12.         android:layout_height="match_parent" />  
    13.   
    14.     <!-- android:layout_gravity="start" tells DrawerLayout to treat  
    15.          this as a sliding drawer on the left side for left-to-right  
    16.          languages and on the right side for right-to-left languages.  
    17.          The drawer is given a fixed width in dp and extends the full height of  
    18.          the container. A solid background is used for contrast  
    19.          with the content view. -->  
    20.     <ListView  
    21.         android:id="@+id/left_drawer"  
    22.         android:layout_width="240dp"  
    23.         android:layout_height="match_parent"  
    24.         android:layout_gravity="start"  
    25.         android:choiceMode="singleChoice"  
    26.         android:divider="@android:color/transparent"  
    27.         android:dividerHeight="0dp"  
    28.         android:background="#111"/>  
    29. </android.support.v4.widget.DrawerLayout>  



    上面的代码中有如下几点需要注意:

    • 显示界面主要内容的View (上面的 FrameLayout ) 必须为DrawerLayout的第一个子View, 原因在于 XML 布局文件中的View顺序为Android系统中的 z-ordering顺序,而抽屉必须出现在内容之上。
    • 显示界面内容的View宽度和高度设置为和父View一样,原因在于当抽屉菜单不可见的时候,界面内容代表整个界面UI。
    • 抽 屉菜单 (上面的 ListView) 必须使用android:layout_gravity属性设置水平的 gravity值 .如果要支持 right-to-left (RTL,从右向左阅读)语言 用 "start" 代替 "left" (当在 RTL语言运行时候,菜单出现在右侧)。
    • 抽屉菜单的宽度为 dp 单位而高度和父View一样。抽屉菜单的宽度应该不超过320dp,这样用户可以在菜单打开的时候看到部分内容界面。


    初始化抽屉菜单
    在您的Activity中需要先初始化抽屉菜单内容,根据您的应用需要抽屉菜单内容的方式可能不一样。但是抽屉菜单通常是一个ListView,所以可以通过Adapter来填充ListView。

    1. @Override  
    2.     protected void onCreate(Bundle savedInstanceState) {  
    3.         super.onCreate(savedInstanceState);  
    4.         setContentView(R.layout.activity_main);  
    5.           
    6.         findView();  
    7.           
    8.         if (savedInstanceState == null) {  
    9.             selectItem(0);  
    10.         }  
    11.     }  
    12.   
    13.     @SuppressLint("NewApi")  
    14.     private void findView() {  
    15.           
    16.         mTitle = mDrawerTitle = getTitle();  
    17.           
    18.         mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);  
    19.         mDrawerList = (ListView) findViewById(R.id.left_drawer);  
    20.   
    21.         // set a custom shadow that overlays the main content when the drawer opens  
    22.         mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);  
    23.           
    24.         mNavMenuTitles = getResources().getStringArray(R.array.nav_drawer_items);  
    25.         // nav drawer icons from resources  
    26.         mNavMenuIconsTypeArray = getResources()  
    27.                     .obtainTypedArray(R.array.nav_drawer_icons);  
    28.               
    29.         mNavDrawerItems = new ArrayList<NavDrawerItem>();  
    30.   
    31.         // adding nav drawer items to array  
    32.         // Home  
    33.         mNavDrawerItems.add(new NavDrawerItem(mNavMenuTitles[0], mNavMenuIconsTypeArray  
    34.                 .getResourceId(0, -1)));  
    35.         // Find People  
    36.         mNavDrawerItems.add(new NavDrawerItem(mNavMenuTitles[1], mNavMenuIconsTypeArray  
    37.                 .getResourceId(1, -1)));  
    38.         // Photos  
    39.         mNavDrawerItems.add(new NavDrawerItem(mNavMenuTitles[2], mNavMenuIconsTypeArray  
    40.                 .getResourceId(2, -1)));  
    41.         // Communities, Will add a counter here  
    42.         mNavDrawerItems.add(new NavDrawerItem(mNavMenuTitles[3], mNavMenuIconsTypeArray  
    43.                 .getResourceId(3, -1), true, "22"));  
    44.         // Pages  
    45.         mNavDrawerItems.add(new NavDrawerItem(mNavMenuTitles[4], mNavMenuIconsTypeArray  
    46.                 .getResourceId(4, -1)));  
    47.         // What's hot, We will add a counter here  
    48.         mNavDrawerItems.add(new NavDrawerItem(mNavMenuTitles[5], mNavMenuIconsTypeArray  
    49.                 .getResourceId(5, -1), true, "50+"));  
    50.   
    51.         // Recycle the typed array  
    52.         mNavMenuIconsTypeArray.recycle();  
    53.           
    54.         // setting the nav drawer list adapter  
    55.         mAdapter = new NavDrawerListAdapter(getApplicationContext(),  
    56.                         mNavDrawerItems);  
    57.         mDrawerList.setAdapter(mAdapter);  
    58.         mDrawerList.setOnItemClickListener(this);  
    59.           



    处理菜单点击事件
    当用户选择菜单List中的条目时,系统会调用  OnItemClickListener的 onItemClick()函数。
    根据您的应用需要onItemClick函数的实现方式可能不同。下面的示例中,选择菜单条目会在程序主界面中插入不同的 Fragment(ID 为 R.id.content_frame 的FrameLayout)。

    1. @Override  
    2. public void onItemClick(AdapterView<?> parent, View view, int position,  
    3.         long id) {  
    4.       
    5.     selectItem(position);  
    6. }  
    7.   
    8. /** 
    9.  * Diplaying fragment view for selected nav drawer list item 
    10.  * */  
    11. private void selectItem(int position) {  
    12.     // update the main content by replacing fragments  
    13.     Fragment fragment = null;  
    14.     switch (position) {  
    15.     case 0:  
    16.         fragment = new HomeFragment();  
    17.         break;  
    18.     case 1:  
    19.         fragment = new FindPeopleFragment();  
    20.         break;  
    21.     case 2:  
    22.         fragment = new PhotosFragment();  
    23.         break;  
    24.     case 3:  
    25.         fragment = new CommunityFragment();  
    26.         break;  
    27.     case 4:  
    28.         fragment = new PagesFragment();  
    29.         break;  
    30.     case 5:  
    31.         fragment = new WhatsHotFragment();  
    32.         break;  
    33.   
    34.     default:  
    35.         break;  
    36.     }  
    37.   
    38.     if (fragment != null) {  
    39.         FragmentManager fragmentManager = getSupportFragmentManager();  
    40.         fragmentManager.beginTransaction()  
    41.                 .replace(R.id.content_frame, fragment).commit();  
    42.   
    43.         // update selected item and title, then close the drawer  
    44.         mDrawerList.setItemChecked(position, true);  
    45.         mDrawerList.setSelection(position);  
    46.         setTitle(mNavMenuTitles[position]);  
    47.         mDrawerLayout.closeDrawer(mDrawerList);  
    48.     } else {  
    49.         // error in creating fragment  
    50.         Log.e("MainActivity", "Error in creating fragment");  
    51.     }  
    52. }  
    53.   
    54. @SuppressLint("NewApi")  
    55. @Override  
    56. public void setTitle(CharSequence title) {  
    57.     mTitle = title;  
    58.     getActionBar().setTitle(mTitle);  
    59. }  



    监听菜单打开关闭事件
    如果需要监听菜单打开关闭事件,则需要调用 DrawerLayout类的 setDrawerListener() 函数,参数为 DrawerLayout.DrawerListener接口的实现。该接口提供了菜单打开关闭等事件的回调函数,例如 onDrawerOpened() 和onDrawerClosed().
    如果您的Activity使用了 action bar,则您可以使用Support库提供的 ActionBarDrawerToggle 类,该类实现了 DrawerLayout.DrawerListener接口,并且您还可以根据需要重写相关的函数。该类实现了菜单和Action bar相关的操作。
    根据在 Navigation Drawer 设计指南中的介绍,当菜单显示的时候您应该根据情况隐藏ActionBar上的功能菜单并且修改ActionBar的标题。下面的代码演示了如何重写 ActionBarDrawerToggle 类的相关函数来实现该功能。

    1. // ActionBarDrawerToggle ties together the the proper interactions  
    2.         // between the sliding drawer and the action bar app icon  
    3.         mDrawerToggle = new ActionBarDrawerToggle(  
    4.                 this,                  /* host Activity */  
    5.                 mDrawerLayout,         /* DrawerLayout object */  
    6.                 R.drawable.ic_drawer,  /* nav drawer image to replace 'Up' caret */  
    7.                 R.string.drawer_open,  /* "open drawer" description for accessibility */  
    8.                 R.string.drawer_close  /* "close drawer" description for accessibility */  
    9.                 ) {  
    10.             public void onDrawerClosed(View view) {  
    11.                 getActionBar().setTitle(mTitle);  
    12.                 invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()  
    13.             }  
    14.   
    15.             public void onDrawerOpened(View drawerView) {  
    16.                 getActionBar().setTitle(mDrawerTitle);  
    17.                 invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()  
    18.             }  
    19.         };  
    20.         mDrawerLayout.setDrawerListener(mDrawerToggle);  
    21.   
    22.     }  
    23.   
    24.     @Override  
    25.     public boolean onCreateOptionsMenu(Menu menu) {  
    26.         // Inflate the menu; this adds items to the action bar if it is present.  
    27.         getMenuInflater().inflate(R.menu.main, menu);  
    28.         return true;  
    29.     }  
    30.       
    31.     /* Called whenever we call invalidateOptionsMenu() */  
    32.     @Override  
    33.     public boolean onPrepareOptionsMenu(Menu menu) {  
    34.         // If the nav drawer is open, hide action items related to the content view  
    35.         boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);  
    36.         menu.findItem(R.id.action_refresh).setVisible(!drawerOpen);  
    37.         return super.onPrepareOptionsMenu(menu);  
    38.     }  



    通过应用图打开或关闭抽屉
    用户可以从屏幕边缘滑动来打开抽屉菜单,如果您使用了 action bar,应该让用户通过点击应用图标也可以打开抽屉菜单。并且应用图标也应该使用一个特殊的图标来指示抽屉菜单。您可以使用 ActionBarDrawerToggle 类来实现这些功能。
    要使用 ActionBarDrawerToggle ,先通过其构造函数来创建该对象,构造函数需要如下参数:

    • 显示抽屉的 Activity 对象。
    • DrawerLayout 对象。
    • 一个用来指示抽屉的 drawable资源。
    • 一个用来描述打开抽屉的文本 (用于支持可访问性)。
    • 一个用来描述关闭抽屉的文本(用于支持可访问性)。

    无论你是否继承 ActionBarDrawerToggle 来实现抽屉监听器,您都需要在Activity的生命周期函数中调用ActionBarDrawerToggle 的一些函数。

    1. // enable ActionBar app icon to behave as action to toggle nav drawer  
    2.         getActionBar().setDisplayHomeAsUpEnabled(true);  
    3.         getActionBar().setHomeButtonEnabled(true);  
    4.           
    5.         // ActionBarDrawerToggle ties together the the proper interactions  
    6.         // between the sliding drawer and the action bar app icon  
    7.         mDrawerToggle = new ActionBarDrawerToggle(  
    8.                 this,                  /* host Activity */  
    9.                 mDrawerLayout,         /* DrawerLayout object */  
    10.                 R.drawable.ic_drawer,  /* nav drawer image to replace 'Up' caret */  
    11.                 R.string.drawer_open,  /* "open drawer" description for accessibility */  
    12.                 R.string.drawer_close  /* "close drawer" description for accessibility */  
    13.                 ) {  
    14.             public void onDrawerClosed(View view) {  
    15.                 getActionBar().setTitle(mTitle);  
    16.                 invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()  
    17.             }  
    18.   
    19.             public void onDrawerOpened(View drawerView) {  
    20.                 getActionBar().setTitle(mDrawerTitle);  
    21.                 invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()  
    22.             }  
    23.         };  
    24.         mDrawerLayout.setDrawerListener(mDrawerToggle);  
    25.   
    26.     }  
    27.   
    28.     @Override  
    29.     public boolean onCreateOptionsMenu(Menu menu) {  
    30.         // Inflate the menu; this adds items to the action bar if it is present.  
    31.         getMenuInflater().inflate(R.menu.main, menu);  
    32.         return true;  
    33.     }  
    34.       
    35.     /* Called whenever we call invalidateOptionsMenu() */  
    36.     @Override  
    37.     public boolean onPrepareOptionsMenu(Menu menu) {  
    38.         // If the nav drawer is open, hide action items related to the content view  
    39.         boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);  
    40.         menu.findItem(R.id.action_refresh).setVisible(!drawerOpen);  
    41.         return super.onPrepareOptionsMenu(menu);  
    42.     }  
    43.       
    44.     @Override  
    45.     public boolean onOptionsItemSelected(MenuItem item) {  
    46.          // The action bar home/up action should open or close the drawer.  
    47.          // ActionBarDrawerToggle will take care of this.  
    48.         if (mDrawerToggle.onOptionsItemSelected(item)) {  
    49.             return true;  
    50.         }  
    51.         // Handle action buttons  
    52.         switch(item.getItemId()) {  
    53.         case R.id.action_search:  
    54.               
    55.              Toast.makeText(this, R.string.action_search, Toast.LENGTH_SHORT).show();  
    56.               
    57.             return true;  
    58.         case R.id.action_refresh:  
    59.               
    60.             Toast.makeText(this, R.string.action_refresh, Toast.LENGTH_SHORT).show();  
    61.               
    62.             return true;  
    63.         default:  
    64.             return super.onOptionsItemSelected(item);  
    65.         }  
    66.     }  
    67.       
    68.     @Override  
    69.     protected void onPostCreate(Bundle savedInstanceState) {  
    70.         super.onPostCreate(savedInstanceState);  
    71.         // Sync the toggle state after onRestoreInstanceState has occurred.  
    72.         mDrawerToggle.syncState();  
    73.     }  
    74.   
    75.     @Override  
    76.     public void onConfigurationChanged(Configuration newConfig) {  
    77.         super.onConfigurationChanged(newConfig);  
    78.         // Pass any configuration change to the drawer toggls  
    79.         mDrawerToggle.onConfigurationChanged(newConfig);  
    80.     }  




    到这来就完啦,还有不懂的可以去参看官方Docs

    http://developer.android.com/training/implementing-navigation/nav-drawer.html



    Demo 下载地址:http://download.csdn.net/detail/fx_sky/6705135

  • 相关阅读:
    Leetcode 50.Pow(x,n) By Python
    Leetcode 347.前K个高频元素 By Python
    Leetcode 414.Fizz Buzz By Python
    Leetcode 237.删除链表中的节点 By Python
    Leetcode 20.有效的括号 By Python
    Leetcode 70.爬楼梯 By Python
    Leetcode 190.颠倒二进制位 By Python
    团体程序设计天梯赛 L1-034. 点赞
    Wannafly挑战赛9 C-列一列
    TZOJ Start
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/4314067.html
Copyright © 2011-2022 走看看