Navigation Drawer详解-Google推出的用来取代Sliding Menu的控件(一

相信Sliding Menu很多人都用过,在Android和iOS的app中,越来越多的开发者都会把自己的菜单界面放在一个列表里,然后让用户通过向右(或者向左)滑动的操作看到应用所有的功能。Google官方的应用也基本都选择了这种交互方式,不同的是,Google使用的是Navigation Drawer,而我们大部分用的还是Sliding Menu。

大家对Sliding Menu这个开源项目可能已经很熟悉了,但是Navigation Drawer我们有些童鞋可能了解的还比较少,它是Google I/O 2013刚推出不久的一个在support v4包里面的一个控件,下面我就通过一个demo跟大家介绍一下Navigation Drawer的使用方法。http://safe.ijiami.cn/

这个demo是google官方的,大家可以到这里下载一下:http://developer.android.com/training/implementing-navigation/nav-drawer.html,我下面写的代码说明也基本就是翻译了一下这个教程,英语比较好的童鞋建议还是直接看官方的吧。

创建一个抽屉

导航抽屉是一个位于屏幕左侧边缘用来显示应用程序导航项的一个面板。导航抽屉在大部分时间是不显示的,但两种情况下会进行显示:一是发生从屏幕左侧边缘向右滑的手势,二是点击了工具栏中应用图标。导航抽屉在SupportLibrary  中提供支持,在使用导航抽屉时,需要符合导航抽屉设计原则(NavigationDrawer),看看你是否有必要创建导航抽屉 。

创建抽屉布局

如果你要添加一个导航抽屉,需要用DrawerLayout来作为用户界面的根视图,DrawerLayout视图下需放置两个子视图,一个是用来显示显示屏幕的主体内容(导航抽屉隐藏的时候),一个是用来显示导航抽屉。

用来显示屏幕主体内容的视图一般是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. <!-- The main content view -->
  7. <FrameLayout
  8. android:id="@+id/content_frame"
  9. android:layout_width="match_parent"
  10. android:layout_height="match_parent" />
  11. <!-- The navigation drawer -->
  12. <ListView android:id="@+id/left_drawer"
  13. android:layout_width="240dp"
  14. android:layout_height="match_parent"
  15. android:layout_gravity="start"
  16. android:choiceMode="singleChoice"
  17. android:divider="@android :color/transparent"
  18. android:dividerHeight="0dp"
  19. android:background="#111"/>
  20. </android.support.v4.widget.DrawerLayout>

复制代码

上面的布局说明了导航抽屉的布局一些非常重要的特点:

1、显示主体内容的视图必须是DrawerLayout下的第一个子视图,因为抽屉视图必须在主体内容视图的上方(意味着DrawerLayout是一个以z轴来布局的控件)

2、显示主体内容的视图必须设置为匹配父视图的高和宽,因为当抽屉视图隐藏的时候显示主体内容的视图代表了整个用户界面

3、抽屉视图的layout_gravity属性值需为“start”,To support right-to-left (RTL) languages,specify the value with "start" insteadof "left" (so the drawer appears on the right when thelayout is RTL)

4、抽屉视图的宽度不宜匹配父视图,应当适当的窄一点,这样就能在抽屉显示的时候还能看到主体内容视图的一部分

初始化抽屉列表

抽屉视图一般包含一个ListView(具体包含的View取决于你的应用),该ListView和平常没什么两样,都需要一个Adapter来填充,也可设置单项选中监听器

  1. public class MainActivity extends Activity {
  2. private String[] mPlanetTitles;
  3. private DrawerLayout mDrawerLayout;
  4. private ListView mDrawerList;
  5. ...
  6. @Override
  7. public void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.activity_main);
  10. mPlanetTitles = getResources().getStringArray(R.array.planets_array);
  11. mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
  12. mDrawerList = (ListView) findViewById(R.id.left_drawer);
  13. // Set the adapter for the list view
  14. mDrawerList.setAdapter(new ArrayAdapter<String>(this,
  15. R.layout.drawer_list_item, mPlanetTitles));
  16. // Set the list‘s click listener
  17. mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
  18. ...
  19. }
  20. }

复制代码

处理导航项选点击事件

导航项的点击事件其实就是包含的ListView项的点击事件,我们需要根据点击的项来相应的改变主体内容,记得上面说过显示主体内容的View运行时一般会是一个Fragment,所以只要把当前的Fragment替换成相应的Fragment就行了

  1. private class DrawerItemClickListener implements ListView.OnItemClickListener {
  2. @Override
  3. public void onItemClick(AdapterView parent, View view, int position, long id) {
  4. selectItem(position);
  5. }
  6. }
  7. /** Swaps fragments in the main content view */
  8. private void selectItem(int position) {
  9. // Create a new fragment and specify the planet to show based on position
  10. Fragment fragment = new PlanetFragment();
  11. Bundle args = new Bundle();
  12. args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
  13. fragment.setArguments(args);
  14. // Insert the fragment by replacing any existing fragment
  15. FragmentManager fragmentManager = getFragmentManager();
  16. fragmentManager.beginTransaction()
  17. .replace(R.id.content_frame, fragment)
  18. .commit();
  19. // Highlight the selected item, update the title, and close the drawer
  20. mDrawerList.setItemChecked(position, true);
  21. setTitle(mPlanetTitles[position]);
  22. mDrawerLayout.closeDrawer(mDrawerList);
  23. }
  24. @Override
  25. public void setTitle(CharSequence title) {
  26. mTitle = title;
  27. getActionBar().setTitle(mTitle);
  28. }

复制代码

监听导航抽屉打开和关闭事件

可以为DrawerLayout设置 DrawerLayout.DrawerListener监听器来监听打开和关闭事件,当导航抽屉打开和关闭时分别会回调onDrawerOpened() 和onDrawerClosed() 方法

但是如果你的Activity包含Action Bar话,你可以选择 ActionBarDrawerToggle 来替代 DrawerListener ,ActionBarDrawerToggle 实现了DrawerListener接口,所以抽屉的打开和关闭事件照样能监听的到,并且使用ActionBarDrawerToggle能促进Action Bar Icon和导航抽屉之间的交互(通过点击icon来打开和关闭导航抽屉),当导航抽屉打开或关闭时Action Bar的状态也应该做相应的改变( NavigationDrawer 中有介绍)

  1. public class MainActivity extends Activity {
  2. private DrawerLayout mDrawerLayout;
  3. private ActionBarDrawerToggle mDrawerToggle;
  4. private CharSequence mDrawerTitle;
  5. private CharSequence mTitle;
  6. ...
  7. @Override
  8. public void onCreate(Bundle savedInstanceState) {
  9. super.onCreate(savedInstanceState);
  10. setContentView(R.layout.activity_main);
  11. ...
  12. mTitle = mDrawerTitle = getTitle();
  13. mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
  14. mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
  15. R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) {
  16. /** Called when a drawer has settled in a completely closed state. */
  17. public void onDrawerClosed(View view) {
  18. getActionBar().setTitle(mTitle);
  19. invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
  20. }
  21. /** Called when a drawer has settled in a completely open state. */
  22. public void onDrawerOpened(View drawerView) {
  23. getActionBar().setTitle(mDrawerTitle);
  24. invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
  25. }
  26. };
  27. // Set the drawer toggle as the DrawerListener
  28. mDrawerLayout.setDrawerListener(mDrawerToggle);
  29. }
  30. /* Called whenever we call invalidateOptionsMenu() */
  31. @Override
  32. public boolean onPrepareOptionsMenu(Menu menu) {
  33. // If the nav drawer is open, hide action items related to the content view
  34. boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
  35. menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
  36. return super.onPrepareOptionsMenu(menu);
  37. }
  38. }

复制代码

点击应用图标来打开和关闭导航抽屉

前面我们是介绍过通过手势来打开和关闭导航抽屉,但是如果Activity包含Action Bar的话,当我们点击应用图标时也能打开和关闭导航抽屉,而且我们也需要通过图标来指示导航抽屉当前的状态,如果我们是使用ActionBarDrawerToggle类的话,可以通过设置构造方法的参数来做到这一点,它的构造方法参数有五个,分别代表:宿主Activity、DrawerLayout、导航抽屉打开时应用图标、导航抽屉打开时描述文本、导航抽屉关闭时描述文本

还有一点要注意的是,当手机屏幕的配置环境发生变化时(横竖屏切换),导航抽屉的配置也需改变,当宿主Activity的onRestoreInstanceState方法调用的时候,导航抽屉的状态也需进行同步,可在onPostCreate方法中进行同步,具体的可以看如下代码

  1. public class MainActivity extends Activity {
  2. private DrawerLayout mDrawerLayout;
  3. private ActionBarDrawerToggle mDrawerToggle;
  4. ...
  5. public void onCreate(Bundle savedInstanceState) {
  6. ...
  7. mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
  8. mDrawerToggle = new ActionBarDrawerToggle(
  9. this, /* host Activity */
  10. mDrawerLayout, /* DrawerLayout object */
  11. R.drawable.ic_drawer, /* nav drawer icon to replace ‘Up‘ caret */
  12. R.string.drawer_open, /* "open drawer" description */
  13. R.string.drawer_close /* "close drawer" description */
  14. ) {
  15. /** Called when a drawer has settled in a completely closed state. */
  16. public void onDrawerClosed(View view) {
  17. getActionBar().setTitle(mTitle);
  18. }
  19. /** Called when a drawer has settled in a completely open state. */
  20. public void onDrawerOpened(View drawerView) {
  21. getActionBar().setTitle(mDrawerTitle);
  22. }
  23. };
  24. // Set the drawer toggle as the DrawerListener
  25. mDrawerLayout.setDrawerListener(mDrawerToggle);
  26. getActionBar().setDisplayHomeAsUpEnabled(true);
  27. getActionBar().setHomeButtonEnabled(true);
  28. }
  29. @Override
  30. protected void onPostCreate(Bundle savedInstanceState) {
  31. super.onPostCreate(savedInstanceState);
  32. // Sync the toggle state after onRestoreInstanceState has occurred.
  33. mDrawerToggle.syncState();
  34. }
  35. @Override
  36. public void onConfigurationChanged(Configuration newConfig) {
  37. super.onConfigurationChanged(newConfig);
  38. mDrawerToggle.onConfigurationChanged(newConfig);
  39. }
  40. @Override
  41. public boolean onOptionsItemSelected(MenuItem item) {
  42. // Pass the event to ActionBarDrawerToggle, if it returns
  43. // true, then it has handled the app icon touch event
  44. if (mDrawerToggle.onOptionsItemSelected(item)) {
  45. return true;
  46. }
  47. // Handle your other action bar items...
  48. return super.onOptionsItemSelected(item);
  49. }
  50. ...
  51. }

复制代码

几张运行的截图:

时间: 2024-10-09 07:21:07

Navigation Drawer详解-Google推出的用来取代Sliding Menu的控件(一的相关文章

Navigation Drawer详解-Google推出的用来取代Sliding Menu的控件(二

第一篇我们就google官方给出的Navigation Drawer demo做了一个简单的介绍,细心的童鞋可能已经发现问题了,google虽然是在support v4中添加的这个控件,但是他给的demo中却使用了ActionBar!ActionBar是在3.0才出现的控件,我们如果想在2.X的版本上同时使用ActionBar和Navigation Drawer,该怎么办呢?http://www.ijiami.cn/treg 其实这个也很简单,我们只需要使用一个开源的library就可以完成了:

Android菜单详解(一)——理解android中的Menu

前言 今天看了pro android 3中menu这一章,对Android的整个menu体系有了进一步的了解,故整理下笔记与大家分享. PS:强烈推荐<Pro Android 3>,是我至今为止看到的最好的一本android书,中文版出到<精通Android 2>. 理解Android的菜单 菜单是许多应用程序不可或缺的一部分,Android中更是如此,所有搭载Android系统的手机甚至都要有一个"Menu"键,由此可见菜单在Android程序中的特殊性.An

Xamarin.Forms中 Navigation,NavigationPage详解

1.Xamarin Forms下有四个成员类:Element,VisualElement,Page,NavigationPage 基类为Element,继承的子类分别是VisualElement,Page,NavigationPage. 2.Navigation 为VisualElement的一个成员对象,该对象是INavigation接口类型的. 3.INavigation接口中有5个方法,如下 namespace Xamarin.Forms { public interface INavig

Navigation寻路详解

说明:从今天开始,我阿赵打算写一些简单的教程,方便自己日后回顾,或者方便刚入门的朋友学习.水平有限请勿见怪.不过请尊重码字截图录屏的劳动,如需转载请先告诉我.谢谢! unity自从3.5版本之后,增加了NavMesh寻路的功能.在此之前,unity用户只能通过第三方插件(如Astar寻路插件)等做寻路功能.阿赵我也使用过A*寻路插件,A*的原理并不复杂,有兴趣的朋友可以自己百度一下.不过由于不是自带的功能,所以在设定网格和烘焙的过程难免会出现很多不便.NavMesh作为unity自带的功能,用法

ANDROID L——Material Design详解(视图和阴影)

转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! Android L: 昨天凌晨Google刚刚确认Android L就是Android Lollipop(5.0). Google之前就已经提前推出了Android L Developer Preview(开发者预览版)来帮助开发者更快的了解Android特性,而不久前也推出了64位的模拟器镜像,而且首次搭载Android L系统的Nexus 6和 Nexus 9也即将上市. 相信And

android:ToolBar详解

这篇文章因为是台湾人写的,语言风格很别致.本文在原文的基础上做了一些微调(主要是繁体字的问题). 今年(2014) 的 google i/o 发表令多数人为之一亮的 material design,而 google 也从「google i/o 2014」 开始,大家也陆陆续续地看到其更新的 android app 皆套用了这个设计介面.当然,这个设计介面著实让大家感到惊艳外,更让 android 开发者开始担心未来 app 的界面处理了. 不过,所幸有着之前 actionbar 的经验后,and

Android Design Support Library使用详解

Android Design Support Library使用详解 Google在2015的IO大会上,给我们带来了更加详细的Material Design设计规范,同时,也给我们带来了全新的Android Design Support Library,在这个support库里面,Google给我们提供了更加规范的MD设计风格的控件.最重要的是,Android Design Support Library的兼容性更广,直接可以向下兼容到Android 2.2.这不得不说是一个良心之作. 使用S

ANDROID – TOOLBAR 上的 NAVIGATION DRAWER(转)

在 Material Design 釋出後,Google 也開始陸續更新了 Google app 的介面,讓大家有個範例可以看.而過去大力推動的 actionbar 自然而然也成了眾開發者觀注的部份:其中的 up button 的設定在前一篇所介紹的 Toolbar 也已看到.這邊還未提到的一個部份是 material design 中有提到的人機互動效果,簡言之,就是讓使用者明顯地感受到在操作 app 時,可以獲得明顯的回應,從而得到豐富地操作體驗感:因此,在剛開始釋出的幾支 Google a

Android菜单详解——理解android中的Menu

Android菜单详解--理解android中的Menu 前言 今天看了pro android 3中menu这一章,对Android的整个menu体系有了进一步的了解,故整理下笔记与大家分享. PS:强烈推荐<Pro Android 3>,是我至今为止看到的最好的一本android书,中文版出到<精通Android 2>. 理解Android的菜单 菜单是许多应用程序不可或缺的一部分,Android中更是如此,所有搭载Android系统的手机甚至都要有一个"Menu&qu