您的位置:首页 > 移动开发 > Android开发

Android 原生导航 III-Drawer导航

2016-01-31 22:58 489 查看

概述:

Drawer导航栏是用于显示主要导航的控件, 它出现在屏幕的左侧. 大多数时候是隐藏的, 当用户从左侧滑入屏幕或者点击App bar上的图标, 它才会显示. 在Google App中它非常的常用, 也是Android上非常推崇的一种导航方式.

规格:





如上图, 包括四个部分:

1.      名字: Roboto Medium, 14sp, #FFFFFF.

2.      Email: Roboto Regular, 14sp,#FFFFFF.

3.      列表项: Roboto Medium, 14sp, 87% #000000.

4.      副标题: Roboto Medium, 14sp, 54% #000000. 对其到16dp关键线.

内容:

高度: Drawer会占满屏幕的高度, 但是会位于状态栏后方, 位于状态栏后面的部分依然可见, 但是会变暗. 下图是它显示出来的样子.



选中的状态: 在一个条目被选中之后, 该条目会变成符合app主颜色的颜色(或者 #000000 100%)来表示自己被选中了. 选中项的所在行会被高亮.



分隔线: 所有在drawer中的分隔线都是铺满整个drawer的, 并且在其上方和下方都有8dp的填充.





上图第一个是分隔线的样子, 第二个是它所占空间的大小. 这里有8个dp的填充.

Drawer行为:

永久显示(桌面系统默认推荐使用): 这种情况下drawer永久显示在屏幕左侧而不能被隐藏. 包括三种风格: 全高度drawer, 在appbar下面的drawer以及悬浮的drawer, 较少使用.

持续导航: 这种drawer可以切换显示和隐藏状态. 默认情况下隐藏, 当选择菜单图标的时候才显示, 并且当用户手动关闭它之前会持续显示. 这种导航可以应用于所有比手机大的屏幕上.

持续导航的迷你模式: 这种模式下, 持续导航改变了它的宽度. 它的隐藏状态会以一个迷你drawer的形式固定在屏幕左边, 并被app bar盖住. 当扩展时它跟标准的drawer一样. 适用于那些需要快速访问的app.下图左边是它的隐藏状态, 右图是显示状态.





临时导航: 这种drawer可以在显示和隐藏间切换, 默认情况下隐藏, 打开的时候会临时覆盖其它的内容, 直到用户选择其中的一个条目. 推荐使用: 平板. 必须使用: 手机. 通常在手机上见到的应该是这种.

Drawer的使用:

下面介绍如何使用支持库中的DrawerLayout API来实现一个drawer导航.

创建一个Drawerlayout:

要想使用drawer layout, 得先在布局中使用DrawerLayout对象作为layout的根元素. 然后在其中添加一个view作为主界面的内容, 也就是当drawer隐藏的时候显示的基础layout, 之后再添加另一个view作为drawer显示的时候的内容. 栗如, 下面这个layout使用了一个DrawerLayout, 并且包含了两个子view: 一个FrameLayout作为主界面, 还有一个ListView作为导航drawer.

<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">

    <!-- The maincontent view -->

    <FrameLayout

        android:id="@+id/content_frame"

        android:layout_width="match_parent"

        android:layout_height="match_parent"/>

    <!-- Thenavigation drawer -->

    <ListView android:id="@+id/left_drawer"

        android:layout_width="240dp"

        android:layout_height="match_parent"

        android:layout_gravity="start"

        android:choiceMode="singleChoice"

        android:divider="@android:color/transparent"

        android:dividerHeight="0dp"

        android:background="#111"/>
</android.support.v4.widget.DrawerLayout>

这里有几个很重要的地方需要注意:

1.      主界面的view(也就是栗子中的FrameLayout)必须是DrawerLayout中的第一个子view(XML order impliesz-ordering and the drawer
must be on top of the content).

2.      主界面的view必须设置为填满parent的长和宽, 因为它是drawer隐藏的时候全部的界面.

3.      Drawer view(上栗中的ListView)必须用android:layout_gravity属性指定它的横向重力. 为了支持从右到左读的语言(RTL),指定该值为”start”而不是”left”(这样的话当layout是RTL的时候, drawer就可以从右边显示出来了).

4.      Drawer view需要使用dp作为单位来指定它的宽度, 并且高度是填满parent的. Drawer的宽度不应该超过320dp,这样用户就可以总能看到主界面的一部分了.

初始化DrawerList:

在我们的activity中, 首先要完成的事情就是初始化drawer的list. 如何实现取决于app的内容, 但是drawer经常跟ListView配合使用, list应该通过一个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()方法来接收drawer的list中的点击事件.

处理导航点击事件:

当用户选择了drawer中list的一项时, 系统会调用OnItemClickListener中的onItemClick(). 在该方法中的逻辑取决于app内容. 下面的栗子中, 选择一个条目会插入一个Fragment到主界面的view中.

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);
}


监听Drawer的显示和隐藏事件:

要监听drawer的显示和隐藏事件, 需要在DrawerLayout上调用setDrawerListener(), 并传递给它DrawerLayout.DrawerListener的实现. 该接口提供了可以监听drawer事件的接口, 比如onDrawerOpened()和onDrawerClosed(),分别对应drawer的显示和隐藏.

但是如果我们的app还包含action bar, 那么我们可以使用ActionBarDrawerToggle类代替DrawerLayout.DrawerListener. ActionBarDrawerToggle类实现了DrawerLayout.DrawerListener接口, 所以我们还是可以使用这些方法, 使用该类还有利于action bar图标跟drawer的交互(下一小节讨论).

我们应该在drawer显示的时候修改action bar的内容, 比如修改title和移除action item. 下面的代码演示了如何通过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);
    }
}


使用APP图标来显示或隐藏Drawer:

用户可以通过从左到右的滑动手势来显示drawer, 但是如果我们同时还使用了action bar, 那么我们应该允许用户通过点击action bar上的app图标来显示或隐藏drawer. 并且app图标应该用一个专用的图标来提醒用户drawer的存在. 我们可以使用ActionBarDrawerToggle来实现这个功能. 想要这个类能按照我们的想法工作, 需要用构造方法来创建一个它的对象, 该方法需要这些参数:

1.      Drawer所在的Activity.

2.      DrawerLayout.

3.      一个drawable资源作为drawer的指示器. 标准的drawer图标可以在这里找到.

4.      一个String资源用于描述”显示drawer”操作.

5.      一个String资源用于描述”隐藏drawer”操作.

然后, 不管我们是否创建一个ActionBarDrawerToggle的子类作为drawer的监听器, 都得在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);
    }

    ...
}


总结:

Drawer使用四步:

1.      定义DrawerLayout. 包括正文和Drawer本身.

2.      初始化Drawer.

3.      处理点击事件.

4.      处理ActionBar和Drawer的关联.

参考: https://developer.android.com/training/implementing-navigation/nav-drawer.html
https://www.google.com/design/spec/patterns/navigation-drawer.html

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息