您的位置:首页 > 移动开发 > Android开发

Android 抽屉导航

2013-11-02 09:50 399 查看
转自:http://blog.csdn.net/lc19850921/article/details/8982315


创建抽屉导航

导航抽屉是在 屏幕左侧边缘的 应用主导航选项的面板. 它大多数时间是隐藏的, 但当用户用手指从屏幕的左侧滑动, 或者当用户点击应用顶部工具栏的应用图标的时候, 它就会显示.

此课程是描述 怎样有效的使用在Support Library中的DrawLayout接口 去实现一个导航抽屉.


创建一个抽屉布局

添加一个抽屉, 声明UI的时候需要吧DrawLayout作为你的布局文件的根视图(root view). 在DrawLayout里面, 添加一个主要内容的视图(当抽屉导航隐藏的时候你的主要的布局文件), 和另一个包含导航抽屉的视图.

举例来说, 下面的布局使用了DrawLayout, 它有2个子视图: 一个FrameLayout包含主要的内容, 一个ListView的导航抽屉.

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

这个布局文件示范了一些重要的布局特征.

主要内容的视图(FrameLayout)必须是DrawLayout的第一个子元素, 因为导航抽屉是在主要内容视图的上面.
主要内容视图设置为匹配父视图的宽度和高度, 因为它代表了整个界面导航抽屉是隐藏的.

抽屉视图(ListView)必须指定其水平重力与android:layout_gravity属性。支持从右到左(RTL)语言,指定值与 
"start"
 代替 
"left"
(所以抽屉里出现在布局的右侧当布局是RTL时).

抽屉视图指定其宽度用dp单位和高度匹配父视图。抽屉里的宽度不能超过320 dp, 所以用户总是可以看到主要内容视图的一部分.


初始化抽屉列表

在你的Activity中, 第一件事就是初始化导航抽屉列表里面的元素, 你如何做取决于你的应用程序的内容,但一个导航抽屉通常包括一个ListView, 因此清单应该由一个Adapter填充(例如ArrayAdapter或SimpleCursorAdapter).

例如, 这里演示了如何用String array来初始化一个导航列表.

public class MainActivity extends Activity {  

    private String[] mPlanetTitles;  

    private ListView mDrawerList;  

    ...  

  

    @Override  

    public void onCreate(Bundle savedInstanceState) {  

        super.onCreate(savedInstanceState);  

        setContentView(R.layout.activity_main);  

  

        mPlanetTitles = getResources().getStringArray(R.array.planets_array);  

        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()去接收导航抽屉列表的点击事件. 下一节将展示如何实现这个接口,当用户选择一个Item时改变内容视图.


处理导航点击事件

当用户选择了抽屉列表里面的一个Item时, 系统调用onItemClickListener上的onItemClick(), 给setOnItemClickListener().

你在onItemClick()方法里面做什么, 取决于你的app实现的结构. 在下面的例子中, 选择每一个Item都会在主要内容的布局中插入一个不同的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  

    mDrawer.setItemChecked(position, true);  

    setTitle(mPlanetTitles[position]);  

    mDrawerLayout.closeDrawer(mDrawer);  

}  

  

@Override  

public void setTitle(CharSequence title) {  

    mTitle = title;  

    getActionBar().setTitle(mTitle);  

}  


监听打开和关闭事件

侦听抽屉打开和关闭事件,调用你的DrawerLayout setDrawerListener(), 并将其传递给DrawerLayout.DrawerListener的实现. 这个接口提供了回调抽屉事件, 如onDrawerOpened()和onDrawerClosed ()。

然而, 相对于实现DrawerLayout.DrawerListener, 如果你的Activity包括工具栏, 可以代替继承ActionBarDrawerToggle类. ActionBarDrawerToggle实现了DrawerLayout.DrawerListener. 所以你仍然可以覆盖这些回调, 但它也有助于正确的交互行为, 在工具栏的图标和导航抽屉之间(下一节将进一步讨论)。

就像在导航抽屉设计指南一样,当抽屉是可见的时候, 你应该修改工具栏的内容, 如改变标题和删除操作Item. 下面的代码用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) {  

                getActionBar().setTitle(mTitle);  

                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()  

            }  

  

            /** Called when a drawer has settled in a completely open state. */  

            public void onDrawerOpened(View 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构造函数参数和其他所需的步骤来设置它来处理工具栏的图标.


打开关闭应用图标

用户可以打开和关闭导航抽屉, 通过手指从屏幕左侧的边缘滑动, 但如果你使用工具栏, 你应该也能允许用户打开和关闭它, 通过触摸应用程序图标. 应用程序图标也可以显示一个特殊的图标关于导航抽屉的状态. 你可以实现所有这些行为通过使用ActionBarDrawerToggle, 如前一节所示。

让ActionBarDrawerToggle工作, 创建一个它的实例用它的构造方法, 这就需要以下参数:

持有抽屉的Activity.
DrawerLayout对象.
一个Drawable资源作为抽屉指示器.
字符串资源描述"打开抽屉"动作.
字符串资源描述"关闭抽屉"动作.

然后, 无论你是否已经创建了一个ActionBarDrawerToggle的子类作为你的抽屉的Listener, 你需要在几个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) {  

                getActionBar().setTitle(mTitle);  

            }  

  

            /** Called when a drawer has settled in a completely open state. */  

            public void onDrawerOpened(View 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);  

    }  

  

    ...  

}  

使用最新的android-support-v4.jar

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

     ...  

    <!-- The navigation drawer -->    

    <ListView  

        android:id="@+id/left_drawer"  

        android:layout_width="120dp"  

        android:layout_height="match_parent"  

        android:layout_gravity="start"  

        android:choiceMode="singleChoice"  

        android:divider="@android:color/transparent"  

        android:dividerHeight="0dp"  

        android:background="#EEA9B8"/>    

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

    /* 抽屉导航变量 */  

    private DrawerLayout mDrawerLayout;  

    private ListView mDrawerList;  

    private ActionBarDrawerToggle mDrawerToggle;  

  

...  

  

        /* 抽屉导航相关 */  

        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);  

        mDrawerList = (ListView) findViewById(R.id.left_drawer);  

        mDrawerLayout.setDrawerShadow(R.drawable.draw, GravityCompat.RELATIVE_HORIZONTAL_GRAVITY_MASK);  

  

        mDrawerList.setAdapter(new SimpleAdapter(this, getDrawerItems(false),  

                R.layout.drawer_item, new String[] { "drawer_img",  

                        "drawer_title" }, new int[] { R.id.drawer_img,  

                        R.id.drawer_title }));  

  

        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());  

        mDrawerToggle = new ActionBarDrawerToggle(  

                this,                  /* host Activity */  

                mDrawerLayout,         /* DrawerLayout object */  

                R.drawable.draw,  /* nav drawer image to replace 'Up' caret */  

                R.string.search_label,  /* "open drawer" description for accessibility */  

                R.string.defalut_text  /* "close drawer" description for accessibility */  

                ) {  

            public void onDrawerClosed(View view) {  

                getActionBar().setTitle("onDrawerClosed");  

                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()  

            }  

  

            public void onDrawerOpened(View drawerView) {  

                getActionBar().setTitle("onDrawerOpened");  

                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()  

            }  

        };  

        mDrawerLayout.setDrawerListener(mDrawerToggle);  

  

...  

  

    /** 

     * 监听抽屉导航item点击事件 

     */  

    private class DrawerItemClickListener implements ListView.OnItemClickListener {  

  

        @Override  

        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {  

            selectItem(view, position);  

        }  

    }  

  

    private boolean flag = false;  

    private void selectItem(View view, int position) {  

        if (position == 0) {  

            if (!flag) {  

                mDrawerList.setAdapter(new SimpleAdapter(this, getDrawerItems(true),  

                        R.layout.drawer_item, new String[] { "drawer_img",  

                                "drawer_title" }, new int[] { R.id.drawer_img,  

                                R.id.drawer_title }));  

                flag = true;  

            } else {  

                mDrawerList.setAdapter(new SimpleAdapter(this, getDrawerItems(false),  

                        R.layout.drawer_item, new String[] { "drawer_img",  

                                "drawer_title" }, new int[] { R.id.drawer_img,  

                                R.id.drawer_title }));  

                flag = false;  

            }  

        } else {  

            TextView title = (TextView) view.findViewById(R.id.drawer_title);  

            String cityName = title.getText().toString();  

            this.cityInput.setText(cityName);  

        }  

    }  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: