码迷,mamicode.com
首页 > 移动开发 > 详细

Android学习之界面篇(七)侧滑菜单的实现

时间:2016-05-02 02:23:35      阅读:449      评论:0      收藏:0      [点我收藏+]

标签:

侧滑菜单的实现方式:
  1. SlidingMenu开源库:https://github.com/jfeinstein10/SlidingMenu
  2. DrawerLayout:是2013年谷歌IO大会上由谷歌官方发布的,包含在support v4包中。
接下来按照谷歌官方给定的创建步骤来实现一个侧滑菜单。

Create a Drawer Layout

To add a navigation drawer, declare your user interface with aDrawerLayout object as the root view of your layout.
Inside theDrawerLayout, add one view that contains the main content for the screen (your primary layout when the drawer is hidden) and another view that contains the contents of the navigation drawer.
按照谷歌官方给出的示例创建一个带有Drawer Layout的项目:
activity_main.xml配置如下:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/draw_layout"
    android:layout_height="match_parent"
    android:layout_width="match_parent">

    <!--The main content view-->
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/content_frame">

    </FrameLayout>

    <!--The navigation view-->
    <ListView
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:id="@+id/left_drawer"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:background="#ffffcc"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp">

    </ListView>

</android.support.v4.widget.DrawerLayout>
         

启动项目,通过从屏幕左端滑动来滑出菜单。
注:
android:layout_gravity="start"是从屏幕左边滑动,"end"则为从屏幕右端滑出。
android:choiceMode="singleChoice"模式为单选模式
android:divider="@android:color/transparent"分割线采用原始的透明分割线
android:dividerHeight="0dp"分割线高度为0,不可见。
注意事项:
  1. 主内容视图一定要是DrawerLayout的第一个子视图
  2. 主内容视图宽度高度要匹配父视图,即"match_parent",也就是说:当抽屉隐藏时,要让用户看到主视图的全部内容。
  3. 必须显示指定抽屉视图(如LiistView)的android:layout_gravity属性。
  • android:layout_gravity="start"从左向右滑出菜单
  • android:layout_gravity="end"从右向左滑出菜单
  • 不推荐使用"left" 和"right"
    4.抽屉视图的宽度以dp为单位,请不要超过320dp(为了总能看到一些主内容视图)

Initialize the Drawer List

In your activity, one of the first things to do is initialize the navigation drawer‘s list of items. How you do so depends on the content of your app, but a navigation drawer often consists of a ListView, so the list should be populated by an Adapter (such as ArrayAdapter or SimpleCursorAdapter).
接下来在项目中实现初始化Drawer List的操作。
1.首先对组件进行声明,包括DrawerLayout和ListView。
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
2.使用ArrayList集合来储存菜单项,使用ArrayAdapter对ListView的内容进行填充。
//使用集合来储存侧滑菜单的菜单项
private ArrayList<String> menuLists;
//使用ArrayAdapter来对ListView的内容进行填充
private ArrayAdapter<String> adapter;
3.在onCreate方法中对z组件进行查找和初始化数据操作。
mDrawerLayout= (DrawerLayout) findViewById(R.id.draw_layout);
mDrawerList= (ListView) findViewById(R.id.left_drawer);


//初始化menulists
menuLists=new ArrayList<String>();
for (int i=0;i<5;i++){
    menuLists.add("测试菜单"+i);
}
//初始化adapter
adapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,menuLists);
//为侧边菜单填充上内容
mDrawerList.setAdapter(adapter);
技术分享

Handle Navigation Click Events

When the user selects an item in the drawer‘s list, the system calls onItemClick() on theOnItemClickListener given to setOnItemClickListener().
What you do in the onItemClick() method depends on how you‘ve implemented your app structure
1.为菜单项添加点击事件监听器,并让主类实现事件监听器接口
mDrawerList.setOnItemClickListener(this);
2.复写事件监听器中的方法,动态插入一个Fragment到FrameLayout中去
public void onItemClick(AdapterView<?> parentView view, int position, long id) {
    //动态插入一个FragmentFrameLayout当中
    Fragment contentFragment=new ContentFragment();
    Bundle args=new Bundle();
    args.putString("text",menuLists.get(position));

    contentFragment.setArguments(args);//?
    //新建一个Fragment
    FragmentManager fm=getFragmentManager();
    fm.beginTransaction().replace(R.id.content_frame,contentFragment).commit();

    //点击完成后关闭菜单栏
    mDrawerLayout.closeDrawer(mDrawerList);


}
3.新建一Fragment ContentFragment,对应配置文件为fragment_content.xml
fragment_content.xml配置如下:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/content_frame"
    tools:context="com.example.icarus.drawerlayoutusing.ContentFragment">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView"
        android:textSize="25sp"
         />

</FrameLayout>
ContentFragment.java具体代码:
public class ContentFragment extends Fragment {
    private TextView textView;


    @Override
    public View onCreateView(LayoutInflater inflaterViewGroup container,
                             Bundle savedInstanceState) {
        //动态加载视图
        View view=inflater.inflate(R.layout.fragment_content,container,false);
        //查找组件id
        textView= (TextView) view.findViewById(R.id.textView);
        //通过Arguments来传递数据
        String text=getArguments().getString("text");
        //textview设置文字
        textView.setText(text);
        //返回加载的视图
        return view;
    }

}

技术分享
问题:
Activity重新创建时,会重新构建它所管理的Fragment,原先的Fragment的字段值将会全部丢失,但是通过Fragment.setArguments(Bundle bundle)方法设置的bundle会保留下来。所以尽量使用Fragment.setArguments(Bundle bundle)方式来传递参数

Listen for Open and Close Events

To listen for drawer open and close events, call setDrawerListener() on your DrawerLayout and pass it an implementation of DrawerLayout.DrawerListener. This interface provides callbacks for drawer events such asonDrawerOpened() and onDrawerClosed().

However, rather than implementing the DrawerLayout.DrawerListener, if your activity includes the action bar, you can instead extend the ActionBarDrawerToggle class. The ActionBarDrawerToggle implementsDrawerLayout.DrawerListener so you can still override those callbacks, but it also facilitates the proper interaction behavior between the action bar icon and the navigation drawer (discussed further in the next section).

As discussed in the Navigation Drawer design guide, you should modify the contents of the action bar when the drawer is visible, such as to change the title and remove action items that are contextual to the main content. 
知识点介绍:
1.mDrawerLayout.setDrawerListener(DrawerLayout.DrawerListener);
2.ActionBarDrawerToggle是 DrawerLayout.DrawerListener的具体实现类。
   1)改变android.R.id.home图标(构造方法)
   2)Drawer拉出、隐藏,带有android.R.id.home动画效果(syncState())
   3)监听Drawer拉出、隐藏事件
3.复写ActionBarDrawerToggle的onDrawerOpended()和onDrawerClosed()以监听抽屉拉出或隐藏事件。
4.复写Activity中的onPostCreate()方法和onConfigurationChange()方法,是为了结合syncState()方法来s实现左上角图标动画的效果。当设备的y一些参数发生变化时(屏幕旋转等)就会调用onConfigurationChange方法,在方法中对ActionBarDrawerToggle进行配置。

在代码中实现:
(一)设置菜单被拉出时Title文字的改变

1.首先声明一个ActionBarDrawerToggle,注意是support.v7包中的(support.v4包中的已经失效)
使用v7替换v4方法请看:ActionBarDrawerToggle is Deprecated
private ActionBarDrawerToggle mDrawerToggle;
2.接着初始化ActionBarDrawerToggle,(具体参数为:ActionBarDrawerToggle(Activity activity, 
DrawerLayout drawerLayout, int openDrawerContentD
escRes, int closeDrawerContentDescRes))并复写其中的onDrawerOpended()和onDrawerClosed()方法来实现拉出或隐藏抽屉时对Title的更改。
注:使用v7包的时候得使用getSupportActionBar()来设置Title信息
mDrawerToggle=new ActionBarDrawerToggle(this,mDrawerLayout,
        R.string.drawer_open,R.string.drawer_close){
    /**
     * 当抽屉被打开是执行
     设置抽屉被打开时的Title
     * 通过getActionBar()来改变
     @param drawerView
     */
    @Override
    public void onDrawerOpened(View drawerView) {
        super.onDrawerOpened(drawerView);
        //BUG:此处产生空指针异常,使用getSupportActionBar()
        //getActionBar().setTitle("请选择");

        getSupportActionBar().setTitle("请选择");
        invalidateOptionsMenu();//重绘actionbar上的菜单项,会自动调用onPrepareOptionsMenu方法
    }

    /**
     * 当抽屉被关闭时执行
     设置抽屉被关闭时的Title
     * @param drawerView
     */
    @Override
    public void onDrawerClosed(View drawerView) {
        super.onDrawerClosed(drawerView);
        getSupportActionBar().setTitle(mTitle);
        invalidateOptionsMenu();//重绘actionbar上的菜单项
    }
};
3.给DrawerLayout添加DrawerListener。setDrawerListener以失效,使用addDrawerListener
mDrawerLayout.addDrawerListener(mDrawerToggle);


(二)在ActionBar上添加搜索图标
1.在res中新建menu文件夹,在其中添加main.xml,其中
android:showAsAction。
  这个属性可接受的值有:
  1、always:这个值会使菜单项一直显示在Action Bar上。
  2、ifRoom:如果有足够的空间,这个值会使菜单项显示在Action Bar上。
  3、never:这个值使菜单项永远都不出现在Action Bar上。
  4、withText:这个值使菜单项和它的图标,菜单文本一起显示。
main.xml配置如下:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
  <item
      android:id="@+id/action_websearch"
      android:icon="@drawable/action_search"
      android:title="webSearch"
      app:showAsAction="ifRoom|withText"/>
</menu>
2.在MainActivity中使用onCreateOptionsMenu()来加载menu
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main,menu);
    return true;
}
3.在执行invalidateOptionsMenu()方法时会调用onPrepareOptionsMenu(),复写此方法来实现菜单图标的显示状态。首先先获取Drawer的打开状态,当Drawer打开时菜单图标被隐藏,当Drawer关闭时显示菜单图标。即菜单图标的显示状态与Drawer的打开状态正好相反。
public boolean onPrepareOptionsMenu(Menu menu) {
    //获取Drawer的打开状态
    boolean isDrawerOpen=mDrawerLayout.isDrawerOpen(mDrawerList);
    //menuItem的可见状态进行改变,总是跟Drawer的打开状态相反
    menu.findItem(R.id.action_websearch).setVisible(!isDrawerOpen);
    return super.onPrepareOptionsMenu(menu);
}
4.使用onOptionsItemSelected()方法来为菜单项设置点击事件。让其使用系统浏览器打开指定的网页(百度)。
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.action_websearch:
            Intent intent=new Intent();
            intent.setAction("android.intent.action.VIEW");
            Uri uri=Uri.parse("http://www.baidu.com");
            intent.setData(uri);
            startActivity(intent);
            break;
    }
    return super.onOptionsItemSelected(item);
}
技术分享

Open and Close with the App Icon

Users can open and close the navigation drawer with a swipe gesture from or towards the left edge of the screen, but if you‘re using the action bar, you should also allow users to open and close it by touching the app icon. And the app icon should also indicate the presence of the navigation drawer with a special icon. You can implement all this behavior by using the ActionBarDrawerToggle shown in the previous section.

To make ActionBarDrawerToggle work, create an instance of it with its constructor, which requires the following arguments:

  • The Activity hosting the drawer.
  • The DrawerLayout.
  • A drawable resource to use as the drawer indicator.

    The standard navigation drawer icon is available in the Download the Action Bar Icon Pack.

  • A String resource to describe the "open drawer" action (for accessibility).
  • A String resource to describe the "close drawer" action (for accessibility).
Then, whether or not you‘ve created a subclass of ActionBarDrawerToggle as your drawer listener, you need to call upon your ActionBarDrawerToggle in a few places throughout your activity lifecycle:
我们希望使用app的图标来打开和关闭侧边栏,根据谷歌开发者文档
1.首先打开ActionBar Icon的功能
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
2.使左上角的Home-Button可用,因为左上角的Home-Button也属于menu的一种所以点击时会回调onOptionItemSelected方法。
getSupportActionBar().setHomeButtonEnabled(true);
3.在 onOptionItemSelected方法中将ActionBar上的图标与Drawer结合起来。
if (mDrawerToggle.onOptionsItemSelected(item)){
    return true;
}
4.需要将ActionDrawerToggler与DrawerLayout的状态同步 ,将ActionBarDrawerTaggler中的drawer图标,设置为ActionBar中的Home-Button的icon
public void onPostCreate(Bundle savedInstanceStatePersistableBundle persistentState) {
    super.onPostCreate(savedInstanceStatepersistentState);
    mDrawerToggle.syncState();
}
5.谷歌开发者文档建议使用onConfigurationChanged方法 ,当屏幕旋转等发生Configuration变化的时候执行
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    mDrawerToggle.onConfigurationChanged(newConfig);
}
技术分享

到此,我们使用谷歌开发者文档提供的DrawerLayout成功完成了侧滑菜单的开发!
项目源码下载:

Android学习之界面篇(七)侧滑菜单的实现

标签:

原文地址:http://blog.csdn.net/icarus_wang/article/details/51292359

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!