Android 创建抽屉导航

抽屉导航非常火,非常好用,但是怎么实现呢?

创建一个DrawerLayout的布局

首先将 DrawerLayout 作为 根view,然后在其中添加两个子view:

这两个子view一上一下(固定的),分别对应的 主体内容 和 隐藏内容(也就是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">
    <!-- 一个可能会动态添加的Fragmentlayout -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <!-- 一个用作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>

要注意的几点是:

  • 主体内容一定是第一个子view,而且高宽必须match_parent
  • drawer的内容一定要指明 在水平方向的 gravity,用 start 代替 left 表示这个 drawer是在左边的
  • drawer的宽度不能超过320dp

实现一个DrawerList

一般来说 Drawer 都是带有一个 ListView 的,一个Listview也就对应一歌adapter,一个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);

        // 给Listview添加一个适配器
        mDrawerList.setAdapter(new ArrayAdapter<String>(this,
                R.layout.drawer_list_item, mPlanetTitles));
        // 添加点击事件,添加点击事件
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

        ...
    }
}

处理点击事件

当Drawer的item被点击之后,我们需要将对应的Fragment放入当前的fragmentLayout之中去,代码如下:

private class DrawerItemClickListener implements ListView.OnItemClickListener {
    @Override
    public void onItemClick(AdapterView parent, View view, int position, long id) {
        // 衔接上面的代码,点击之后,根据点击的按钮的位置,选择相应的Fragment
        selectItem(position);
    }
}

/** 替换主内容中的Fragment */
private void selectItem(int position) {
    // 通过position来创建一个fragment,
    Fragment fragment = new PlanetFragment();
    Bundle args = new Bundle();
    args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
    fragment.setArguments(args);

    // 用这个新创建的fragment替换之前的fragment
    FragmentManager fragmentManager = getFragmentManager();
    fragmentManager.beginTransaction()
                   .replace(R.id.content_frame, fragment)
                   .commit();

    // 将Listview中选中的那个选项 高亮显示
    mDrawerList.setItemChecked(position, true);

    // 根据postion设置当前的bar显示的标题
    setTitle(mPlanetTitles[position]);

    // 将drawer关闭,也就是缩回抽屉
    mDrawerLayout.closeDrawer(mDrawerList);
}

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

监听打开和关闭drawer的事件

创建menu

为了实现对drawer的打开和关闭事件的监听,我们要在 DrawerLayout 上添加一个 setDrawerListener 的方法,传入参数为 DrawerLayout.DrawerListener 的一个 实现。

而且,如果你的activity里有actionbar,那么比起一个DrawerLayout.DrawerListener的实现,不如直接继承类 ActionBarDrawerToggle 。这个类也实现的需要的接口。同时 它也确定一些 actionbar的图标 和 导航drawer 之间的行为
比如 : 通过点击bar上的按钮来打开drawer的交互

代码如下:

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) {

            /** 当drawer处于完全关闭的情况下调用 */
            public void onDrawerClosed(View view) {
                super.onDrawerClosed(view);
                getActionBar().setTitle(mTitle);
                invalidateOptionsMenu(); // 这是个静态方法吗?
            }

            /** 当drawer处于完全打开的情况下调用 */
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                getActionBar().setTitle(mDrawerTitle);
                invalidateOptionsMenu();
            }
        };

        // 把这个toggle设置为这个drawer的listener
        mDrawerLayout.setDrawerListener(mDrawerToggle);
    }

    // 以下两个方法可以创建一个menu在actionbar中
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }

    /* Called whenever we call invalidateOptionsMenu() */
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // 获取当前的Drawer是打开的还是关闭的
        boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
        // 如果是开的,那就隐藏对应的view,如果是关的那么就要显示对应的view
        menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    }
}

打开和关闭 actionbar icon

衔接上面对drawer的打开和关闭的监听。

一般来说,用户打开drawer都是通过,手势或者点击边缘。但是如果你使用了action bar 那么你也得允许用户通过 action bar 来打开和关闭 drawer.

而且这个 icon 应该是 表明是可以打开和关闭drawer的特殊 icon

还有,不管你是否要使用ActionbarToggle的子类,你都必须在程序的一些地方调用你都ActionbarToggle

代码如下:

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

        mDrawerLayout.setDrawerListener(mDrawerToggle);

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




    //  这个方法是在activity初始化完成之后调用的,一般不实现这个方法。这个是让一些系统类做最后的初始化的
    //  注意,自定义的代码一定要写在 super方法之后
    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // 同步开关状态
        mDrawerToggle.syncState();
    }

    //  这个方法是在设备参数改变的时候调用的,比如:屏幕方向倒置等
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    // 当有menu种的item被选中的时候调用
    @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);
    }

    ...
}

在这个案例中,官方给的控件有些已经显示为不支持了,如果感兴趣可以去github搜索第三方的drawer来使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值