【原创+译文】官方文档中声明的如何创建抽屉导航栏(Navigation Drawer)

如需转载请注明出处:http://www.cnblogs.com/ghylzwsb/p/5831759.html

创建一个抽屉导航栏

抽屉式导航栏是显示在屏幕的左边缘,它是应用程序的主导航选项面板。它大部分时间是处于隐藏状态的,但是当用户从屏幕的左边缘挥动手指时它就会显示出来,而在应用程序的顶层,用户触摸操作栏上的应用程序图标也可以将其显示出来。

本课程介绍在可用的API 支持库下如何实现导航抽屉DrawerLayout。

首先我们可以看一下最终的效果图:

1、创建一个抽屉布局文件(Drawer Layout)

要添加一个抽屉式导航,首先你必须要声明你的用户界面的根布局为DrawerLayout对象。在DrawerLayout里面,添加一个主视图内容的view对象(当抽屉被隐藏的时候显示在屏幕上的 视图)和另外一个包含抽屉导航视图的view对象。

例如,下面的布局采用了包含两个子视图的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
 7     <!-- 主视图 -->
 8     <FrameLayout
 9         android:id="@+id/content_frame"
10         android:layout_width="match_parent"
11         android:layout_height="match_parent" />
12
13     <!-- 抽屉视图 -->
14     <ListView
15         android:id="@+id/left_drawer"
16         android:layout_width="240dp"
17         android:layout_height="match_parent"
18         android:layout_gravity="start"
19         android:background="#111"
20         android:choiceMode="singleChoice"
21         android:divider="@android:color/transparent"
22         android:dividerHeight="0dp" />
23
24 </android.support.v4.widget.DrawerLayout>

这个布局文件演示了一些比较重要的布局特点,如下:

  • 主内容视图(上面的FrameLayout)必须是DrawerLayout布局对象的第一个子view对象,这是因为xml文件意味着是z排序(即空间上的上下排序,也就是说抽屉导航栏应该位于住内容视图的垂直上方)。
  • 主内容视图的view对象的两个属性:layout_width、layout_height必须是match_parent的,这是因为当抽屉导航栏被隐藏的时候他便是整个UI。
  • 抽屉视图要指定其宽度的单位为dp,高度与父视图相匹配。抽屉的宽度应该不超过320dp,这样用户可以随时看到主要内容视图的一些部分。
  • 抽屉视图(ListView)必须用 android:layout_gravity 属性来指定他的水平重力方向。为了支持从右到左(RTL)的语言,应该要指定其属性为"start" ,而不是"left" 。

2、初始化抽屉列表

在你的Activity中,首先要做的事之一就是初始化抽屉导航栏中的列表项。至于你要如何做取决于你的应用程序中的内容,但是通常情况下抽屉导航栏都是包含了一个ListView,所以列表应该由Adapter来填充(如ArrayAdapter或者SimpleCursorAdapter)。

例如下面将告诉你如何用字符串数组初始化抽屉导航栏列表:

public class MainActivity extends Activity {
    private String[] mPlanetTitles;
    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    ...

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

        mPlanetTitles = getResources().getStringArray(R.array.planets_array);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.left_drawer);

        // Set the adapter for the list view
        mDrawerList.setAdapter(new ArrayAdapter<String>(this,
                R.layout.drawer_list_item, mPlanetTitles));
        // Set the list‘s click listener
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

        ...
    }
}

此代码还调用setOnItemClickListener()来接收抽屉导航栏列表的点击事件。下一节将展示如何实现此接口,以实现当用户选择一个项目后更改主内容视图。

3、处理导航的点击事件

当用户选择在抽屉导航栏里列表中的项目时,系统调用OnItemClickListener接口中的onItemClick()方法以返回给OnItemClickListener() 。你要在onItemClick()方法中做什么样的处理取决于你如何实现你的的应用程序结构。在下面的例子中,你将可以实现下面的内容:当点击抽屉导航栏中列表项里的item时,将会在住内容视图中插入一个不同的Fragment。(FrameLayout的id为 R.id.content_frame)。

private class DrawerItemClickListener implements ListView.OnItemClickListener {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        selectItem(position);
    }
}

/** Swaps fragments in the main content view */
private void selectItem(int position) {
    // Create a new fragment and specify the planet to show based on position
    Fragment fragment = new PlanetFragment();
    Bundle args = new Bundle();
    args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
    fragment.setArguments(args);

    // Insert the fragment by replacing any existing fragment
    FragmentManager fragmentManager = getFragmentManager();
    fragmentManager.beginTransaction()
                   .replace(R.id.content_frame, fragment)
                   .commit();

    // Highlight the selected item, update the title, and close the drawer
    mDrawerList.setItemChecked(position, true);
    setTitle(mPlanetTitles[position]);
    mDrawerLayout.closeDrawer(mDrawerList);
}

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

4、监听打开以及关闭抽屉导航栏的事件

要监听抽屉打开和关闭事件,在你的DrawerLayout中调用setDrawerListener()并传入一个DrawerLayout.DrawerListener接口 。此接口为抽屉导航栏提供了回掉方法,如onDrawerOpened()和onDrawerClosed()。

然而,除了实现DrawerLayout.DrawerListener接口之外,如果你的Activity包含了ActionBar,你也可以继承ActionBarDrawerToggle这个类,这是因为ActionBarDrawerToggle类实现DrawerLayout.DrawerListener接口,所以你仍然可以复写这些方法,但是这对ActionBar图标和抽屉的交互也有一定的帮助。

正如在抽屉导航设计指南讨论的一样,当抽屉处于可见状态时你应该要修改操作栏(ActionBar)的内容,例如你应该要改变标题,并移除与主内容试图相关的列表项。下面的代码演示了如何通过实例化ActionBarDrawerToggle类并复写在DrawerLayout.DrawerListener中的回调方法,以达到这样的目的:

public class MainActivity extends Activity {
    private DrawerLayout mDrawerLayout;
    private ActionBarDrawerToggle mDrawerToggle;
    private CharSequence mDrawerTitle;
    private CharSequence mTitle;
    ...

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

        mTitle = mDrawerTitle = getTitle();
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
                R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) {

            /** Called when a drawer has settled in a completely closed state. */
            public void onDrawerClosed(View view) {
                super.onDrawerClosed(view);
                getActionBar().setTitle(mTitle);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }

            /** Called when a drawer has settled in a completely open state. */
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                getActionBar().setTitle(mDrawerTitle);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }
        };

        // Set the drawer toggle as the DrawerListener
        mDrawerLayout.setDrawerListener(mDrawerToggle);
    }

    /* Called whenever we call invalidateOptionsMenu() */
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // If the nav drawer is open, hide action items related to the content view
        boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
        menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    }
}

下一节将介绍ActionBarDrawerToggle构造函数的参数,并设置它来处理与操作栏图标交互所需的其他步骤。

5、如何通过应用程序图标打开或关闭抽屉导航栏

用户可以通过来自或朝向屏幕的左边缘轻扫的手势来打开与关闭抽屉式导航栏,但如果你正在使用操作栏(ActionBar) ,你也应该允许用户通过触摸应用程序图标的方式打开或者关闭抽屉导航栏。而应用程序图标也应用一个特殊的图标注明抽屉的存在。你也可以通过实现上一节讲到的ActionBarDrawerToggle来实现这些行为。

为了使ActionBarDrawerToggle发挥作用,你将需要创建它的一个实例与它的构造方法,这需要下列参数:

  • 持有该抽屉的Activity
  • 一个DrawerLayout
  • 用于作为抽屉指标的绘制资源(drawable resource),这里会提供一个android官方提供的图标包:Android_Design_Icons_20130926.zip
  • 用来形容“打开抽屉”这一操作的字符串资源
  • 用来形容“关闭抽屉”这一操作的字符串资源

最后,不管你是否已经创建了ActionBarDrawerToggle的子类作为抽屉的监听器,你还是需要在整个Activity的生命周期中的几个地方调用ActionBarDrawerToggle:

public class MainActivity extends Activity {
    private DrawerLayout mDrawerLayout;
    private ActionBarDrawerToggle mDrawerToggle;
    ...

    public void onCreate(Bundle savedInstanceState) {
        ...

        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerToggle = new ActionBarDrawerToggle(
                this,                  /* host Activity */
                mDrawerLayout,         /* DrawerLayout object */
                R.drawable.ic_drawer,  /* nav drawer icon to replace ‘Up‘ caret */
                R.string.drawer_open,  /* "open drawer" description */
                R.string.drawer_close  /* "close drawer" description */
                ) {

            /** Called when a drawer has settled in a completely closed state. */
            public void onDrawerClosed(View view) {
                super.onDrawerClosed(view);
                getActionBar().setTitle(mTitle);
            }

            /** Called when a drawer has settled in a completely open state. */
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                getActionBar().setTitle(mDrawerTitle);
            }
        };

        // Set the drawer toggle as the DrawerListener
        mDrawerLayout.setDrawerListener(mDrawerToggle);

        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);
    }

    @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);
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Pass the event to ActionBarDrawerToggle, if it returns
        // true, then it has handled the app icon touch event
        if (mDrawerToggle.onOptionsItemSelected(item)) {
          return true;
        }
        // Handle your other action bar items...

        return super.onOptionsItemSelected(item);
    }

    ...
}

教程的最后,我提供了项目的下载地址:DrawerLayout_sample.rar,希望这个教程能够帮到你。

BOB

2016-09-03

时间: 2024-12-24 21:33:38

【原创+译文】官方文档中声明的如何创建抽屉导航栏(Navigation Drawer)的相关文章

swift官方文档中的函数闭包是怎么理解的?

官方文档中的16页: numbers.map({ (number: Int) -> Int in let result = 3 * number return result }) 不知道这个怎么用,更不知道它所说的要写个把奇数改成0的方法. swift官方文档中的函数闭包是怎么理解的?

swift官方文档中的switch中case let x where x.hasSuffix(&quot;pepper&quot;)是什么意思?

在官方文档中,看到这句.但不明白什么意思. let vegetable = "red pepper" switch vegetable { case "celery": let vegetableComment = "Add some raisins and make ants on a log" case "cocumber", "watercress": let vegetableComment = &

Oracle 官方文档 结构说明(教你如何快速从官方文档中获取需要的知识)

这里以11g官方文档为例: 今天来说说怎么快速的从官方文档中得到自己需要的知识. 在线官方文档地址: http://tahiti.oracle.com/ 几乎囊括了 oracle各种产品的文档(oracle db12c的文档还没更新上来) 离线下载地址: www.oracle.com 这个不多说了 以11g官方网文档为例: Getting started 页面: 这里包括一些最基础的文档链接. Concept,里面包括了Oracle数据库里面的一些基本概念和原理.比如说数据库的逻辑结构.物理结构

tensorflow官方文档中的sub 和mul中的函数已经在API中改名了

在照着tensorflow 官方文档和极客学院中tensorflow中文文档学习tensorflow时,遇到下面的两个问题: 1)AttributeError: module 'tensorflow' has no attribute 'sub' #进入一个交互式Tensorflow会话 import tensorflow as tf sess = tf.InteractiveSession() x = tf.Variable([1.0,2.0]) a = tf.constant([3.0,3.

Django1.7官方文档中的tutorial——翻译

写下你的第一个Django应用,第一部分 让我们通过例子来学习. 通过这篇指南,我们将会带你浏览一遍一个基本投票应用的创建. 它由两部分组成: 1一个让人们查看投票和进行投票的公共站点 2一个让你添加,改变和删除投票的管理站点 我们假设你已经安装了Django.你可以检查Django是否被安装以及是哪个版本的通过运行下列命令: python -c “import django; print(django.get_version())” 如果Django被安装了,你应该会看到你安装的版本,否则,你

docker官方文档中的dns,link,expose,publish

link是过时的了,尽量不要用. dns内部集成,也可以用外部. expose只是用于记录,并不真的. publish是否起作用,也要看情况,是否被占用端口. -------------------------------------- Embedded DNS server Docker daemon runs an embedded DNS server which provides DNS resolution among containers connected to the same

摘录ECMAScript官方文档中重要的两段话

Every object created by a constructor has an implicit reference (called the object’s prototype) to the value of itsconstructor’s "prototype" property. Furthermore, a prototype may have a non-null implicit reference to itsprototype, and so on; th

Spark官方文档中推荐的硬件配置

1.关于存储: 1).可能的话,Spark节点与HDFS节点是一一对应的 2).如果做不到,那至少保证Spark节点与HDFS节点是一个局域网内 2.关于硬盘: 1).官方推荐每台机子4-8个硬盘,然后不需要做RAID(因为本身你的硬盘就是用来做),配置 spark.local.dir结点啦 3.关于内存 1).官方建议给spark配置当前机器内存的75%比较合理 2).当一个节点的内存超过200G的时候,建议将当前节点的worker换成两个,平均分配你的资源.  因为超过200G后,JAVA的

有关于OpenStack的Rocky版官方文档部署中的一些错误

OpenStack-Rocky版本的错误错误1:在装包时包下载失败,在确定系统源没有问题之后,发现Ping不通百度.最后,添加了DNS解决的,说明没有添加DNS(/etc/resolv.conf). 错误2:作为admin用户,请求身份验证令牌时发生错误,应为端口错误,在配置的时候,使用的是5000,下面命令中测试使用的是35357,所以错了.[[email protected] ~]# openstack --os-auth-url http://controller:35357/v3 \ -