Creating a Navigation Drawer

原文链接:http://developer.android.com/training/implementing-navigation/nav-drawer.html


A Navigation Drawer,有时候也叫SlidingMenu。就是类似知乎、网易新闻、唯品会那样的隐藏在屏幕左边的菜单栏。可以通过手指从左往右滑动,或者点击ActionBar上的一个icon来显示Menu。

在使用这个控件到你的应用中之前,你需要读一下这个网页http://developer.android.com/design/patterns/navigation-drawer.html来了解一下Navigation Drawer的用户用例和设计原则。


创建一个Drawer布局:

为了添加一个Navigation Drawer,需要将DrawerLayout作为你的layout的根view。再添加一个view来存放主要的内容,添加一个view来存放Navigation 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 main content view -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <!-- The navigation 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>

这个layout展示了一些重要的布局特征:

1.主容器(FrameLayout)必须放在DrawerLayout中第一个的位置,因为XML顺序代表了z轴,而drawer必须放在content的上面。

2.主容器的宽高设置成填充父元素,因为在drawer隐藏时,主容器代表整个UI界面。

3.drawer控件必须申明android:layout_gravity属性。为了支持RTL语言,使用了"start"值而不是"left"值。(这样当layout是RTL时,drawer就出现在右边)。

4.drawer的宽度用dp表示,而高度是填充父元素。为了始终能看见主容器的一部分,drawer的宽度应该不超过320dp。


初始化Drawer的List:

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的子控件的点击事件。下面的代码会展示当用户选择了一个item时,怎样实现这个接口来改变主容器的内容。


处理Navigation的点击事件:

在下面的例子中,选中Drawer List的一个子控件就向主容器中插入一个不同的Fragment。

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添加一个DrawerLayout.DrawerListener这个接口提供onDrawerOpened()和onDrawClosed()的回调函数。

如果你的应用包含action bar,那你也可以继承ActionBarDrawerToggle。因为ActionBarDrawerToggle实现了DrawerLayout.DrawerListener,所以你仍然可以重写这些回调函数。并且这样也可以使ActionBar和Navigation Drawer有更好的交互。

当Drawer可见时,你需要修改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的构造参数,以及设置它来处理与ActionBar icon交互所需要的其他步骤。

通过App Icon来打开和关闭Drawer:

用户可以通过手势滑动来打开或关闭Drawer,但是如果你使用Actionbar,你应该允许用户通过点击App icon来打开和关闭Drawer。并且需要一个特定的icon来指示Drawer的打开和关闭。你可以通过ActionBarDrawerToggle来实现所有的这些行为。

为了使一个ActionBarDrawerToggle具备这些功能,在通过构造方法创建它的实例的时候,需要下面的参数:

1.包含这个Drawer的Activity。

2.DrawerLayout。

3.一个用来指示Drawer的图片资源。

4.一个字符串资源来描述“open drawer”动作。

5.一个字符串资源来描述“close 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);
    }

    ...
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值