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

侧滑菜单的实现方式:
  1. SlidingMenu开源库:https://github.com/jfeinstein10/SlidingMenu
  2. DrawerLayout:是2013年谷歌IO大会上由谷歌官方发布的,包含在support v4包中。
       官方定义: http://developer.android.com/reference/android/support/v4/widget/DrawerLayout.html
          使用说明: http://developer.android.com/training/implementing-navigation/nav-drawer.html
接下来按照谷歌官方给定的创建步骤来实现一个侧滑菜单。
Create a Drawer Layout
To add a navigation drawer, declare your user interface with a DrawerLayout  object as the root view of your layout.
Inside the DrawerLayout , 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) ;
Android学习之界面篇(七)侧滑菜单的实现_第1张图片
Handle Navigation Click Events
When the user selects an item in the drawer's list, the system calls  onItemClick()  on the OnItemClickListener  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<?> parent View view , int position , long id) {
     // 动态插入一个 Fragment FrameLayout 当中
    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 inflater ViewGroup 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 ;
    }

}

问题:
1. 为什么要用Fragment.setArguments(Bundle bundle)来传递参数 
Activity重新创建时,会重新构建它所管理的Fragment,原先的Fragment的字段值将会全部丢失,但是通过Fragment.setArguments(Bundle bundle)方法设置的bundle会保留下来。所以尽量使用Fragment.setArguments(Bundle bundle)方式来传递参数
具体: http://blog.csdn.net/tu_bingbing/article/details/24143249
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 savedInstanceState PersistableBundle persistentState) {
     super.onPostCreate(savedInstanceState persistentState) ;
     mDrawerToggle.syncState() ;
}
5.谷歌开发者文档建议使用onConfigurationChanged方法 , 当屏幕旋转等发生Configuration变化的时候执行
public void  onConfigurationChanged(Configuration newConfig) {
     super.onConfigurationChanged(newConfig) ;
     mDrawerToggle.onConfigurationChanged(newConfig) ;
}

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

你可能感兴趣的:(android,界面,DrawerLayout,侧滑菜单)