Side nav 屉子导航

Side nav 抽屉导航
本文围绕以下三个部分展开:

一、DrawerLayout 抽屉布局
二、案例
        附   代码补充
三、案例二:抽屉布局结合SwipeTab





一、DrawerLayout 抽屉布局

Side nav 屉子导航


        1. DrawerLayout的使用场景

        (1)超过三个*视图(否则可用 Tab 导航)

        (2)需要从底层视图切换导航位置

        (3)分支视图层次较深

        2. 实现抽屉导航

        相关类:

        (1)抽屉布局:android.support.v4.widget.DrawerLayout

        (2)抽屉把手:android.support.v4.app.ActionBarDrawerToggle

        需要在工程中先导入 support-v4 。


二、案例

Side nav 屉子导航


Side nav 屉子导航


Side nav 屉子导航


        1. 抽屉布局需要用到v4支持包,因此先导入v4支持包:在 build.gradle 中加入以下导包语句:

compile 'com.android.support:support-v4:21.0.3'


        2. 在 strings.xml 中定义所需字符串:

<resources>
  <string name="app_name">DrawerNav</string>

  <string name="action_settings">Settings</string>

  <string name="drawer_open">open</string>
  <string name="drawer_close">close</string>
  <string name="search">搜索</string>
  <string name="title">目录</string>

</resources>


        3. 复制 icon 到 res 下面:

Side nav 屉子导航


        4. 在 menu_main.xml 中定义 search 菜单 (搜索菜单):

<item
      android:id="@+id/action_search"
      android:title="@string/search"
      android:orderInCategory="101"
      android:showAsAction="always"
      android:icon="@drawable/ic_search_white_24dp"/>


        在 menu_main.xml 中,原本就有设置菜单(settings),加入搜索菜单后,界面如下:

Side nav 屉子导航


        menu_main.xml 代码如下:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      tools:context=".MainActivity">
  <item
      android:id="@+id/action_settings"
      android:title="@string/action_settings"
      android:orderInCategory="100"
      android:showAsAction="never"/>

  <item
      android:id="@+id/action_search"
      android:title="@string/search"
      android:orderInCategory="101"
      android:showAsAction="always"
      android:icon="@drawable/ic_search_white_24dp"/>
</menu>


        5. 在 activity_main.xml 中定义内容视图(帧布局)和左侧、右侧两个抽屉:

<android.support.v4.widget.DrawerLayout
    android:id="@+id/drawer_layout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="match_parent">

  <!--内容视图-->
  <FrameLayout
      android:id="@+id/content_layout"
      android:layout_width="match_parent"
      android:layout_height="match_parent"/>

  <!--
  左侧抽屉 :
    因为左侧抽屉,写了一个单独的布局文件 drawer_left,因此要包含进来。
    单独写布局文件,内容可以更丰富一些。
  -->
  <!-- layout_gravity:定义抽屉的位置(start:左侧;end:右侧。) -->
  <include
      layout="@layout/drawer_left"
      android:layout_width="240dp"
      android:layout_height="match_parent"
      android:layout_gravity="start"/>

  <!--
  右侧抽屉 :
    因为右侧抽屉没有单独写布局文件,因此只需写一个控件 ListView 即可。
  -->
  <ListView
      android:id="@+id/right_drawer"
      android:layout_width="240dp"
      android:layout_height="match_parent"
      android:layout_gravity="end"
      android:background="@android:color/white"/>

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


        其中,左侧抽屉写了一个单独的布局文件 drawer_left.xml,其界面如下:

Side nav 屉子导航


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="@android:color/white">

  <LinearLayout
      android:orientation="vertical"
      android:layout_width="match_parent"
      android:layout_height="150dp"
      android:background="@android:color/darker_gray">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@mipmap/ic_launcher"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/app_name"
        android:layout_gravity="center"
        android:paddingTop="30dp"/>

  </LinearLayout>

  <ListView
      android:id="@+id/listView"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:choiceMode="singleChoice"
      android:divider="@android:color/transparent"
      android:dividerHeight="0dp"/>
</LinearLayout>

    <!--
    上面的 LinearLayout 不会被调用,因此不需要写 id。
    下面的 ListView 会在里面添加内容,因此需要写 id。
    -->


        6. MainActivity 。 声明变量。

// 声明变量
    private String[] data = {"选项一", "选项二", "选项三", "选项四", "选项五"};
    private DrawerLayout drawerLayout;
    private ActionBarDrawerToggle toggle;
    private ListView listView;


        7. MainActivity 。 初始化变量(同时设置抽屉的阴影、设置显示抽屉把手)。

// 初始化变量
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        // 设置抽屉的阴影
        drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, Gravity.START);
        drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, Gravity.END);
        // 显示 Home 按钮(此处显示抽屉把手)
        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);


        8. MainActivity 。 创建抽屉把手(可以部署到手机上看效果)。

   // 创建抽屉把手(看效果)
        // 参数:上下文,抽屉布局对象,把手菜单图标,打开抽屉的文本,关闭抽屉的文本
        toggle = new ActionBarDrawerToggle(this,
                drawerLayout,
                R.drawable.ic_menu_white_24dp,
                R.string.drawer_open,
                R.string.drawer_close) {
            // 抽屉打开
            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                getActionBar().setTitle(getString(R.string.title));
            }

            // 抽屉关闭
            @Override
            public void onDrawerClosed(View drawerView) {
                super.onDrawerClosed(drawerView);

            }
        };

        // 同步状态(更新 Home 位置显示的图标)
        toggle.syncState();
        // 设置监听器
        drawerLayout.setDrawerListener(toggle);


        9. MainActivity 。 写菜单事件(搜索图标)。完成后可以在手机上部署看效果。

// 菜单 (看效果:要重绘菜单)
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        // 8.1 控制搜索图标的显示/隐藏
        // 左侧抽屉打开,隐藏操作栏按钮
        // 左侧抽屉关闭,显示操作栏按钮
        boolean isOpen = drawerLayout.isDrawerOpen(Gravity.START);
        menu.findItem(R.id.action_search).setVisible(!isOpen);
        return true;
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // 8.2 点击抽屉把手,打开/关闭抽屉
        if (toggle.onOptionsItemSelected(item)) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }


        接着在上一步的“创建抽屉把手”中的打开抽屉(onDrawerOpened)和关闭抽屉(onDrawerClosed)的类中,重新绘制菜单(不重新绘制的时候,菜单没有改变)

invalidateOptionsMenu();


        10. MainActivity 。 初始化左侧抽屉。

        (1)在 onCreate()方法中,调用自己创建的初始化左侧抽屉的方法:initLeftDrawer() 。

// 初始化左侧抽屉
        initLeftDrawer();


        (2)在initLeftDrawer()方法中,将 左侧抽屉的listView(列表框)、适配器、数据 进行绑定 。

   // 左侧抽屉的listView(列表框)、适配器、数据 进行绑定
        // 之所以能找到 listView,是因为 activity_main.xml 把它 include 了。
        listView = (ListView) findViewById(R.id.listView);
        ArrayAdapter adapter = new ArrayAdapter(this,
                android.R.layout.simple_list_item_activated_1, data);
        // 设置单选模式
        listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        listView.setAdapter(adapter);


        补充:
        simple_list_item_1 :有一个控件。
        simple_list_item_2 :有两个控件。
        simple_list_item_activated_1 : 有一个控件。当选项选中时,背景色改变(即为激活状态)
        simple_list_item_activated_2 : 有两个控件。当选项选中时,背景色改变(即为激活状态)

        (3)在initLeftDrawer()方法中,写 点击左侧抽屉ListView(列表框)的事件。

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                // 点击ListView中的项的时候,就设置标题
                getActionBar().setTitle(data[position]);
                // 点击完项后,关闭左侧抽屉
                drawerLayout.closeDrawer(Gravity.START);




        11. MainActivity 。 创建两个碎片:NewsFragment & fragment_news.xml,TechFragment & fragment_tech.xml。

        12.当选中左侧抽屉中ListView中的不同选项的时候,使用不同的 碎片 替换 内容视图。

        (1)在“声明变量”部分,定义 碎片管理器

// 定义 碎片管理器
    private FragmentManager fm;


        (2)在“初始化变量”部分,获得 碎片管理器

// 获得 碎片管理器
        fm = this.getFragmentManager();


        (3)在“初始化左侧抽屉”的点击ListView事件部分,当选中“选项一”的时候,用 News 碎片 替换 内容视图;当选中“选项二”的时候,用 Tech 碎片 替换 内容视图。

FragmentTransaction ft = fm.beginTransaction();
                switch (position) {
                    case 0:
                        ft.replace(R.id.content_layout, new NewsFragment());
                        break;
                    case 1:
                        ft.replace(R.id.content_layout, new TechFragment());
                        break;
                    default:
                        break;
                }
                // 提交事务
                ft.commit();



        附   代码补充

Side nav 屉子导航


        MainActivity

package com.xiangdong.drawernav;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;


public class MainActivity extends Activity {
    // 5. 声明变量
    private String[] data = {"选项一", "选项二", "选项三", "选项四", "选项五"};
    private DrawerLayout drawerLayout;
    private ActionBarDrawerToggle toggle;
    private ListView listView;

    // 11.1 定义 碎片管理器
    private FragmentManager fm;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 6. 初始化变量
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        // 设置抽屉的阴影
        drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, Gravity.START);
        drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, Gravity.END);
        // 显示 Home 按钮(此处显示抽屉把手)
        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);

        // 11.2 获得 碎片管理器
        fm = this.getFragmentManager();

        // 7. 创建抽屉把手(看效果)
        // 参数:上下文,抽屉布局对象,把手菜单图标,打开抽屉的文本,关闭抽屉的文本
        toggle = new ActionBarDrawerToggle(this,
                drawerLayout,
                R.drawable.ic_menu_white_24dp,
                R.string.drawer_open,
                R.string.drawer_close) {
            // 抽屉打开
            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                // 8.3重新绘制菜单 (不重新绘制的时候,菜单没有改变)
                invalidateOptionsMenu();
                getActionBar().setTitle(getString(R.string.title));
            }

            // 抽屉关闭
            @Override
            public void onDrawerClosed(View drawerView) {
                super.onDrawerClosed(drawerView);
                // 8.3 重新绘制菜单
                invalidateOptionsMenu();
            }
        };

        // 同步状态(更新 Home 位置显示的图标)
        toggle.syncState();
        // 设置监听器
        drawerLayout.setDrawerListener(toggle);

        // 9. 初始化左侧抽屉
        initLeftDrawer();
    }

    /**
     * 9. 初始化左侧抽屉
     */
    private void initLeftDrawer() {
        // 9.1 左侧抽屉的listView(列表框)、适配器、数据 进行绑定
        // 之所以能找到 listView,是因为 activity_main.xml 把它 include 了。
        listView = (ListView) findViewById(R.id.listView);
        /*
        simple_list_item_1 :有一个控件。
        simple_list_item_2 :有两个控件。
        simple_list_item_activated_1 : 有一个控件。当选项选中时,背景色改变(即为激活状态)
        simple_list_item_activated_2 : 有两个控件。当选项选中时,背景色改变(即为激活状态)
         */
        ArrayAdapter adapter = new ArrayAdapter(this,
                android.R.layout.simple_list_item_activated_1, data);
        // 设置单选模式
        listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        listView.setAdapter(adapter);

        // 9.2 点击左侧抽屉ListView(列表框)的事件
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                // 点击ListView中的项的时候,就设置标题
                getActionBar().setTitle(data[position]);
                // 点击完项后,关闭左侧抽屉
                drawerLayout.closeDrawer(Gravity.START);

                // 10. 创建碎片(XxxFragment & fragment_Xxx.xml)
                // 11. 使用 碎片 替换 内容视图
                // 11.3
                FragmentTransaction ft = fm.beginTransaction();
                switch (position) {
                    case 0:
                        ft.replace(R.id.content_layout, new NewsFragment());
                        break;
                    case 1:
                        ft.replace(R.id.content_layout, new TechFragment());
                        break;
                    default:
                        break;
                }
                // 提交事务
                ft.commit();

            }
        });

    }


    // 菜单 (看效果:要重绘菜单)
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        // 8.1 控制搜索图标的显示/隐藏
        // 左侧抽屉打开,隐藏操作栏按钮
        // 左侧抽屉关闭,显示操作栏按钮
        boolean isOpen = drawerLayout.isDrawerOpen(Gravity.START);
        menu.findItem(R.id.action_search).setVisible(!isOpen);
        return true;
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // 8.2 点击抽屉把手,打开/关闭抽屉
        if (toggle.onOptionsItemSelected(item)) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}



三、案例二:抽屉布局结合SwipeTab

Side nav 屉子导航


Side nav 屉子导航


        本案例与上一个案例,唯一不同的是,当点击左侧抽屉中的“选项一”后,加载了一个碎片:MainFragment ,该碎片使用了 SwipeTab。

Side nav 屉子导航


        1. strings.xml

<resources>
  <string name="app_name">DrawerNav</string>

  <string name="drawer_open">open</string>
  <string name="drawer_close">close</string>
  <string name="search">搜索</string>
  <string name="title">目录</string>

  <string name="news">新闻</string>
  <string name="tech">科技</string>
  <string name="game">游戏</string>

  <string name="action_settings">Settings</string>

</resources>


        2. menu_main.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      tools:context=".MainActivity">
  <item
      android:id="@+id/action_settings"
      android:orderInCategory="100"
      android:showAsAction="never"
      android:title="@string/action_settings"/>

  <item
      android:id="@+id/action_search"
      android:icon="@drawable/ic_search_white_24dp"
      android:orderInCategory="101"
      android:showAsAction="always"
      android:title="@string/search"/>
</menu>


        3. activity_main.xml

<android.support.v4.widget.DrawerLayout
    android:id="@+id/drawer_layout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <!-- 内容视图 -->
  <FrameLayout
      android:id="@+id/content_layout"
      android:layout_width="match_parent"
      android:layout_height="match_parent"/>

  <!-- 左侧抽屉 -->
  <!--layout_gravity: 定义抽屉的位置(start 左侧,end 右侧)-->
  <include
      layout="@layout/drawer_left"
      android:layout_width="240dp"
      android:layout_height="match_parent"
      android:layout_gravity="start"/>

  <!--右侧抽屉-->
  <ListView
      android:id="@+id/right_drawer"
      android:layout_width="240dp"
      android:layout_height="match_parent"
      android:layout_gravity="end"
      android:background="@android:color/white"/>
</android.support.v4.widget.DrawerLayout>


        4. 三个碎片的布局:

        fragment_news.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"
             tools:context="com.android.drawernav.NewsFragment">

  <TextView
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:text="@string/news"/>

</FrameLayout>


        fragment_tech.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"
             tools:context="com.android.drawernav.TechFragment">

  <TextView
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:text="@string/tech"/>

</FrameLayout>


        fragment_game.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"
             tools:context="com.android.drawernav.GameFragment">

  <TextView
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:text="@string/game"/>

</FrameLayout>


        5. SwipeTab的布局文件和事件:

        (1)fragment_main.xml

<android.support.v4.view.ViewPager
    android:id="@+id/pager"
    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"/>

<!--
  因为要调用,因此要写 id。
-->


        (2)MainFragment

package com.android.drawernav;


import android.app.ActionBar;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


/**
 * A simple {@link Fragment} subclass.
 */
public class MainFragment extends Fragment {
    private ActionBar actionBar;
    private String[] tabs = {"新闻", "科技"};
    private ViewPager viewPager;
    private TabFragmentAdapter adapter;

    public MainFragment() {

    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_main, container, false);
        actionBar = getActivity().getActionBar();

        // 8.创建 ViewPager 适配器
        adapter = new TabFragmentAdapter(getActivity().getSupportFragmentManager());

        // 获得分页控件 (fragment_main.xml)
        viewPager = (ViewPager) view.findViewById(R.id.pager);
        viewPager.setAdapter(adapter);

        // 9. 设置 Pager 改变的监听器
        viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int i, float v, int i1) {

            }

            @Override
            public void onPageSelected(int i) {
                // Pager 改变时后,选中对应的 Tab
                actionBar.setSelectedNavigationItem(i);
            }

            @Override
            public void onPageScrollStateChanged(int i) {

            }
        });

        // 11.设置应用栏导航模式,文本/监听事件
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        if (actionBar.getTabCount() == 0) {
            for (int i = 0; i < tabs.length; i++) {
                actionBar.addTab(actionBar.newTab().setText(tabs[i]).
                        setTabListener(tabListener));
            }
        }else{
           // 获得 已初始化的 actionBar
        }
        return view;
    }

    private class TabFragmentAdapter extends FragmentPagerAdapter {

        public TabFragmentAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int i) {
            switch (i) {
                case 0:
                    // 需要兼容低版本:android.support.v4.app.Fragment
                    return new NewsFragment();
                case 1:
                    return new TechFragment();
                default:
                    return null;
            }
        }

        @Override
        public int getCount() {
            return tabs.length;
        }
    }

    private ActionBar.TabListener tabListener = new ActionBar.TabListener() {

        @Override
        public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
            // 点击 Tab,ViewPager 改变选中项
            viewPager.setCurrentItem(tab.getPosition());
        }

        @Override
        public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {

        }

        @Override
        public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {

        }
    };
}


        6. MainActivity:

package com.android.drawernav;

import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.os.Bundle;

import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;


public class MainActivity extends FragmentActivity {
    // 5.声明变量
    private String[] data = {"选项一", "选项二", "选项三", "选项四", "选项五"};
    private DrawerLayout drawerLayout;
    private ActionBarDrawerToggle toggle;
    private ListView listView;

    private FragmentManager fm;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 6.初始化变量
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        // 设置抽屉的阴影
        drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, Gravity.START);
        drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, Gravity.END);
        // 显示 Home 按钮(此处显示抽屉把手)
        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);

        fm = this.getSupportFragmentManager();

        // 7.创建抽屉把手(看效果)
        // 参数:上下文,抽屉布局对象,把手菜单图标,打开抽屉的文本,关闭抽屉的文本
        toggle = new ActionBarDrawerToggle(this, drawerLayout,
                R.drawable.ic_menu_white_24dp,
                R.string.drawer_open, R.string.drawer_close
        ) {

            // 抽屉打开
            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                // 重建选项菜单
                invalidateOptionsMenu();
                getActionBar().setTitle(getString(R.string.title));
            }

            // 抽屉关闭
            @Override
            public void onDrawerClosed(View drawerView) {
                super.onDrawerClosed(drawerView);
                // 重建选项菜单
                invalidateOptionsMenu();
            }
        };
        // 同步状态(跟新 Home 位置显示的图标)
        toggle.syncState();
        // 设置监听器
        drawerLayout.setDrawerListener(toggle);

        // 9. 初始化左侧抽屉
        initLeftDrawer();
    }

    /**
     * 9.1 初始化左侧抽屉
     */
    private void initLeftDrawer() {
        listView = (ListView) findViewById(R.id.listView);
        // simple_list_item_1 一个控件
        // simple_list_item_2 两个控件
        // simple_list_item_activated_1 当选项选中时,改背景色(激活状态)
        ArrayAdapter adapter = new ArrayAdapter(this,
                android.R.layout.simple_list_item_activated_1, data);
        // 设置单选模式
        listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        listView.setAdapter(adapter);

        // 9.2 点击左侧抽屉列表项的事件处理
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                // 设置标题
                getActionBar().setTitle(data[position]);
                // 关闭抽屉
                drawerLayout.closeDrawer(Gravity.START);

                // 10. 创建 XxxFragment & fragment_xxx.xml
                // 11. 使用 Fragment 替换 内容视图
                FragmentTransaction ft = fm.beginTransaction();
                switch (position) {
                    case 0:
                        ft.replace(R.id.content_layout, new MainFragment());
                        break;
                    case 1:
                        ft.replace(R.id.content_layout, new GameFragment());
                        break;
                    default:
                        // 3 / 4 / 5 (省略)
                        break;
                }
                ft.commit();
            }
        });
    }

    // 8. 菜单 [看效果 - 重建选项菜单 invalidateOptionsMenu()]
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        // 8.1 搜索图标 显示/隐藏
        // 左侧抽屉打开,隐藏操作栏按钮;
        // 左侧抽屉关闭,显示操作栏按钮
        boolean isOpen = drawerLayout.isDrawerOpen(Gravity.START);
        menu.findItem(R.id.action_search).setVisible(!isOpen);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // 8.2 点击抽屉把手,打开/关闭抽屉
        if (toggle.onOptionsItemSelected(item)) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}